def GetNextDhcpPacket(self): if self.filedesc and self.binary: packet = dhcp_packet.DhcpPacket() data = self.filedesc.read(4096) packet.DecodePacket(data) return packet elif self.filedesc and not self.binary: packet = dhcp_packet.DhcpPacket() for line in self.filedesc: packet.AddLine(line) return packet
def dhcp_inform(self, packet): mac = decode_mac(packet.GetOption("chaddr")) client_ip = ".".join(map(str, packet.GetOption("ciaddr"))) requested_options = packet.GetOption("parameter_request_list") opt_vals = self.__db.retrieve_dhcp_options( mac=mac, address=client_ip, option_ids=requested_options) ack = dhcp_packet.DhcpPacket() ack.CreateDhcpAckPacketFrom(packet) # FIXME: check the RFC on 'hops' hops = packet.GetOption("hops") if hops: ack.SetOption("hops", hops) self.assign_dhcp_options(options=opt_vals, requested=requested_options, packet=ack) ack.DeleteOption("yiaddr") ack.DeleteOption("ip_address_lease_time") # send an ack self.SendPacket(ack)
def HandleDhcpDiscover(self, packet): clientMacAddress = ":".join('%02x' % i for i in packet.GetHardwareAddress()) try: clientAddress = self.get_address(clientMacAddress) except: return self.memory[clientMacAddress] = clientAddress packet.SetMultipleOptions({'ip_address_lease_time': [0, 2, 0, 0]}) # Think it means 2*256*256 seconds :) offer = dhcp_packet.DhcpPacket() offer.CreateDhcpOfferPacketFrom(packet) self.addBootInfoAndBroadcast(offer, clientAddress)
def HandlePacket(self): if not self.sockets_initialized: self._open_sockets() rlist, wlist, xlist = select.select(self.dhcp_sockets, [], []) s = rlist[0] data, sender = s.recvfrom(self.BUFLEN) packet = dhcp_packet.DhcpPacket() try: packet.DecodePacket(data) except Exception as e: print_exception(e) b64_data = base64.b64encode(data) print("FAILED TO PARSE: %r: %r" % (e, b64_data)) dhcp.get_logger().log(dhcp.logging.ERROR, "IGN/UNPARSABLE: %r" % b64_data) if raven_client: raven_client.captureMessage( "Failed to parse invalid DHCP packet", tags={"server": self.dhcp_socket_info[s]["address"]}, level=dhcp.logging.ERROR, extra={ "b64_data": b64_data, "server_ip_address": self.dhcp_socket_info[s]["address"], "server_interface": self.dhcp_socket_info[s], "t_name": "INVALID", "recvd_from": sender, }, ) return packet.set_sender(sender) packet.set_recv_interface(self.dhcp_socket_info[s]) packet_type = get_packet_type(packet) if packet_type is False: log_packet(packet, prefix="IGN/INVALID TYPE:", raw=True) if not packet.IsDhcpPacket(): log_packet(packet, prefix="IGN/INVALID PKT:", raw=True) self.QueuePacket(packet, packet_type)
def GetNextDhcpPacket(self, timeout=60): data = "" while data == "": data_input, data_output, data_except = select.select( [self.dhcp_socket], [], [], timeout) if (data_input != []): (data, source_address) = self.dhcp_socket.recvfrom(2048) else: return None if data != "": packet = dhcp_packet.DhcpPacket() packet.source_address = source_address packet.DecodePacket(data) self.HandleDhcpAll(packet) if packet.IsDhcpDiscoverPacket(): self.HandleDhcpDiscover(packet) elif packet.IsDhcpRequestPacket(): self.HandleDhcpRequest(packet) elif packet.IsDhcpDeclinePacket(): self.HandleDhcpDecline(packet) elif packet.IsDhcpReleasePacket(): self.HandleDhcpRelease(packet) elif packet.IsDhcpInformPacket(): self.HandleDhcpInform(packet) elif packet.IsDhcpOfferPacket(): self.HandleDhcpOffer(packet) elif packet.IsDhcpAckPacket(): self.HandleDhcpAck(packet) elif packet.IsDhcpNackPacket(): self.HandleDhcpNack(packet) else: self.HandleDhcpUnknown(packet) return packet
def dhcp_request(self, packet): # check to see if lease is still valid, if so: extend lease and send an ACK router = ".".join(map(str, packet.GetOption("giaddr"))) mac = decode_mac(packet.GetOption("chaddr")) ciaddr = ".".join(map(str, packet.GetOption("ciaddr"))) recv_if = packet.get_recv_interface() if router == "0.0.0.0": if recv_if["broadcast"]: # hey, local DHCP traffic! router = recv_if["address"] # FIXME: If ciaddr is set, we should use a unicast message to client requested_ip = bytes_to_ip(packet, "request_ip_address") if not requested_ip: requested_ip = ciaddr if not requested_ip: raise Exception("This really needs fixed...") if router == "0.0.0.0" and recv_if["unicast"]: # this was a unicast packet, I hope... router = requested_ip # giaddr = ".".join(map(str, packet.GetOption("giaddr"))) print("mac: %s, requested address: %s" % (mac, requested_ip)) # make sure a valid lease exists try: lease = self.__db.make_dhcp_lease( mac, router, requested_ip, discover=False, server_address=recv_if["address"], ) except error.InvalidIPAddress: lease = { "address": None, "error": "address not allowed for client" } print("got lease: %s" % str(lease)) if lease["address"] != requested_ip: # FIXME: Send a DHCP NAK if authoritative print( "Lease invalid... client wants %s, but db gave us %s -- sending NAK" % (requested_ip, lease["address"])) nak = dhcp_packet.DhcpPacket() # Why use 'NAK' when we can say 'NACK' (which means nothing to me) nak.CreateDhcpNackPacketFrom(packet) hops = packet.GetOption("hops") if hops: nak.SetOption("hops", hops) self.SendPacket(nak, giaddr=router) return ack = dhcp_packet.DhcpPacket() ack.CreateDhcpAckPacketFrom(packet) # make a list of requested DHCP options requested_options = packet.GetOption("parameter_request_list") print("requested_options: %s" % requested_options) if lease["hostname"] and DhcpOptions[ "host_name"] in requested_options: ack.SetOption("host_name", list(map(ord, lease["hostname"]))) # get option/value pairs from database opt_vals = self.__db.retrieve_dhcp_options( mac=mac, address=requested_ip, option_ids=requested_options) print("opt_vals: %s" % str(opt_vals)) print("Got lease %s from database" % lease) # set them on the packet # Options to request from the DB (address/gateway are assumed) ack.SetOption("yiaddr", ip_to_list(lease["address"])) hops = packet.GetOption("hops") if hops: ack.SetOption("hops", hops) ack.SetOption("ip_address_lease_time", int_to_4_bytes(lease["lease_time"])) # TEST ack.SetOption("subnet_mask", ip_to_list(lease["netmask"])) ack.SetOption("broadcast_address", ip_to_list(lease["broadcast"])) # TEST ack.SetOption("router", ip_to_list(lease["router"])) self.assign_dhcp_options(options=opt_vals, requested=requested_options, packet=ack) # send an ack print(" > sending ack") self.SendPacket(ack) print( "######################################################################" )
def dhcp_discover(self, packet): router = ".".join(map(str, packet.GetOption("giaddr"))) mac = decode_mac(packet.GetOption("chaddr")) requested_ip = bytes_to_ip(packet, "request_ip_address") recv_if = packet.get_recv_interface() if router == "0.0.0.0": if recv_if["broadcast"]: # hey, local DHCP traffic! router = recv_if["address"] if not requested_ip: requested_ip = "0.0.0.0" lease = self.__db.make_dhcp_lease( mac, router, requested_ip, discover=True, server_address=recv_if["address"], ) print("Got lease %s from database" % lease) while self.address_in_use(lease["address"]): print("Address %s in use, marking lease %s as abandoned" % (lease["address"], lease)) dhcp.get_logger().log( dhcp.logging.ERROR, "%-12s Address in use: %(15)s (client: %s)", "ERR/IN_USE:", lease["address"], mac, ) self.__db.mark_abandoned_lease(address=lease["address"]) lease = self.__db.make_dhcp_lease( mac, router, requested_ip, discover=True, server_address=recv_if["address"], ) print("Got new lease %s from database" % lease) # create an offer print("> creating offer") offer = dhcp_packet.DhcpPacket() offer.CreateDhcpOfferPacketFrom(packet) hops = packet.GetOption("hops") if hops: offer.SetOption("hops", hops) # fields # FIXME: get a free lease from the DB # we will need the function to return: the address, the gateway, # the network/netmask/broadcast # FIXME: what about lease/renewal/rebinding_time, etc? # then offer it # Options to request from the DB (address/gateway are assumed) offer.SetOption("yiaddr", ip_to_list(lease["address"])) # options from DB print("setting lease time to %s seconds" % lease["lease_time"]) offer.SetOption("ip_address_lease_time", int_to_4_bytes(lease["lease_time"])) # TEST # offer.SetOption("renewal_time_value",[0,0,0,60]) # TEST # offer.SetOption("rebinding_time_value",[0,0,0,105]) # TEST offer.SetOption("subnet_mask", ip_to_list(lease["netmask"])) offer.SetOption("broadcast_address", ip_to_list(lease["broadcast"])) # TEST offer.SetOption("router", ip_to_list(lease["router"])) # offer.SetOption("hops",[1,]) # TEST: number of hops # make a list of requested DHCP options requested_options = packet.GetOption("parameter_request_list") print("requested_options: %s" % requested_options) if lease["hostname"] and DhcpOptions[ "host_name"] in requested_options: offer.SetOption("host_name", list(map(ord, lease["hostname"]))) # get option/value pairs from database opt_vals = self.__db.retrieve_dhcp_options( mac=mac, address=requested_ip, option_ids=requested_options) print("opt_vals: %s" % str(opt_vals)) self.assign_dhcp_options(options=opt_vals, requested=requested_options, packet=offer) # send an offer print(" > sending offer") self.SendPacket(offer)