def HandlePacket( self ): 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, 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=level, 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
def dhcp_decline(self, packet): mac = decode_mac( packet.GetOption('chaddr') ) requested_ip = '.'.join(map(str,packet.GetOption('request_ip_address'))) if requested_ip != '0.0.0.0': dhcp.get_logger().log(dhcp.logging.ERROR, "%-12s Address in use: %s", 'ERR/DECL:', requested_ip ) self.__db.mark_abandoned_lease( mac=mac, address=requested_ip ) else: dhcp.get_logger().log(dhcp.logging.ERROR, "%-12s Address in use: %s", 'ERR/DECL2:', mac ) self.__db.mark_abandoned_lease( mac=mac )
def log_packet( packet, prefix='', level=dhcp.logging.INFO, raw=False): # This should be called for every incoming or outgoing packet. pkttype,mac,xid,client,giaddr,recvd_from,req_opts = parse_packet(packet) t_name = types[pkttype] if pkttype in types else "INVALID" if giaddr != '0.0.0.0': client_foo = '%s via %s' % (client, giaddr) else: client_foo = str(client) if packet.IsOption('host_name'): host_name=packet.GetOption('host_name') client_foo = '%s [option 12: %s]' % (client_foo, ''.join(map(chr,host_name))) raw_append = '' if raw: raw_data = base64.b64encode(packet._raw_data) if packet._raw_data else packet._raw_data raw_append = " RAW:%r" % raw_data dhcp.get_logger().log(level, "%-12s %-8s %s 0x%08x (%s)%s", prefix, t_name, mac, xid, client_foo, raw_append ) if raven_client and level >= raven_client_min_level or t_name=='decline': if 'IGN' in prefix: if 'LIMIT' in prefix: message = 'request from %s ignored due to rate limiting' % mac elif 'UNAVAIL' in prefix: message = 'unable to find appropriate lease: giaddr=%s' % giaddr else: message = prefix[:-1] elif t_name=='decline': message = 'dhcpdecline from host %s' % mac else: message = "%s %s from %s" % (prefix, t_name.upper(), mac,) requested_ip = bytes_to_ip(packet, 'request_ip_address') raven_client.captureMessage(message, tags={ 'server': packet.get_recv_interface()['address'], }, level=level, extra={ 'server_ip_address': packet.get_recv_interface()['address'], 'server_interface': packet.get_recv_interface(), 't_name': t_name, 'mac': mac, 'xid': xid, 'client': client, 'giaddr': giaddr, 'requested_ip': requested_ip, 'recvd_from': recvd_from, }, )
def log_packet( packet, prefix='', level=dhcp.logging.INFO): # This should be called for every incoming or outgoing packet. pkttype,mac,xid,client,giaddr,recvd_from,req_opts = parse_packet(packet) t_name = types[pkttype] if giaddr != '0.0.0.0': client_foo = '%s via %s' % (client, giaddr) else: client_foo = str(client) dhcp.get_logger().log(level, "%-12s %-8s %s 0x%08x (%s)", prefix, t_name, mac, xid, client_foo )
def dhcp_decline(self, packet): mac = decode_mac(packet.GetOption('chaddr')) requested_ip = '.'.join( map(str, packet.GetOption('request_ip_address'))) if requested_ip != '0.0.0.0': dhcp.get_logger().log(dhcp.logging.ERROR, "%-12s Address in use: %s", 'ERR/DECL:', requested_ip) self.__db.mark_abandoned_lease(mac=mac, address=requested_ip) else: dhcp.get_logger().log(dhcp.logging.ERROR, "%-12s Address in use: %s", 'ERR/DECL2:', mac) self.__db.mark_abandoned_lease(mac=mac)
def bytes_to_ip(packet, opt_name): try: addr = packet.GetOption(opt_name) except: addr = None if not addr: return None if type(addr) != list: raise Exception("Eh?") if len(addr) != 4: logger = dhcp.get_logger() dhcp.get_logger().log(dhcp.logging.ERROR,"INVALID: %r invalid for %s from %s" % (addr, opt_name, decode_mac(packet.GetOption('chaddr')))) return None return '.'.join(map(str, addr))
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 dhcp_decline(self, packet): mac = decode_mac(packet.GetOption("chaddr")) requested_ip = bytes_to_ip(packet, "request_ip_address") if requested_ip and requested_ip != "0.0.0.0": dhcp.get_logger().log( dhcp.logging.ERROR, "%-12s Address in use: %s (from: %s)", "ERR/DECL:", requested_ip, mac, ) self.__db.mark_abandoned_lease(mac=mac, address=requested_ip) else: dhcp.get_logger().log( dhcp.logging.ERROR, "%-12s Address in use: (from: %s)", "ERR/DECL2:", mac, )
def bytes_to_ip(packet, opt_name): try: addr = packet.GetOption(opt_name) except Exception: addr = None if not addr: return None if type(addr) != list: raise Exception("Eh?") if len(addr) != 4: dhcp.get_logger().log( dhcp.logging.ERROR, "INVALID: %r invalid for %s from %s" % (addr, opt_name, decode_mac(packet.GetOption("chaddr"))), ) return None return ".".join(map(str, addr))
def dhcp_discover(self, packet): router = '.'.join(map(str, packet.GetOption('giaddr'))) mac = decode_mac(packet.GetOption('chaddr')) requested_ip = '.'.join( map(str, packet.GetOption('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 = '.'.join(map(str, packet.GetOption('ciaddr'))) if not requested_ip: raise Exception("This really needs fixed...") 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", 'ERR/IN_USE:', lease['address']) 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 = 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", 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)
def log_packet(packet, prefix='', level=dhcp.logging.INFO): # This should be called for every incoming or outgoing packet. pkttype, mac, xid, client, giaddr, recvd_from, req_opts = parse_packet( packet) t_name = types[pkttype] if giaddr != '0.0.0.0': client_foo = '%s via %s' % (client, giaddr) else: client_foo = str(client) if packet.IsOption('host_name'): host_name = packet.GetOption('host_name') client_foo = '%s [option 12: %s]' % (client_foo, ''.join( map(chr, host_name))) dhcp.get_logger().log(level, "%-12s %-8s %s 0x%08x (%s)", prefix, t_name, mac, xid, client_foo) if raven_client and level >= raven_client_min_level or t_name == 'decline': if 'IGN' in prefix: if 'LIMIT' in prefix: message = 'request from %s ignored due to rate limiting' % mac elif 'UNAVAIL' in prefix: message = 'unable to find appropriate lease: giaddr=%s' % giaddr else: message = prefix[:-1] elif t_name == 'decline': message = 'dhcpdecline from host %s' % mac else: message = "%s %s from %s" % ( prefix, t_name.upper(), mac, ) try: requested_ip = packet.GetOption('request_ip_address') except: requested_ip = None if requested_ip: requested_ip = '.'.join(map(str, requested_ip)) raven_client.captureMessage( message, tags={ 'server': packet.get_recv_interface()['address'], }, level=level, extra={ 'server_interface': packet.get_recv_interface(), 't_name': t_name, 'mac': mac, 'xid': xid, 'client': client, 'giaddr': giaddr, 'requested_ip': requested_ip, 'recvd_from': recvd_from, }, )
def dhcp_discover(self, packet): router = '.'.join(map(str,packet.GetOption('giaddr'))) mac = decode_mac( packet.GetOption('chaddr') ) requested_ip = '.'.join(map(str,packet.GetOption('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 = '.'.join(map(str,packet.GetOption('ciaddr'))) if not requested_ip: raise Exception("This really needs fixed...") 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", 'ERR/IN_USE:', lease['address'] ) 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 = 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", 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)
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)
def log_packet(packet, prefix="", level=dhcp.logging.INFO, raw=False): # This should be called for every incoming or outgoing packet. pkttype, mac, xid, client, giaddr, recvd_from, req_opts = parse_packet( packet) t_name = types[pkttype] if pkttype in types else "INVALID" if giaddr != "0.0.0.0": client_foo = "%s via %s" % (client, giaddr) else: client_foo = str(client) if packet.IsOption("host_name"): host_name = packet.GetOption("host_name") client_foo = "%s [option 12: %s]" % (client_foo, "".join( map(chr, host_name))) raw_append = "" if raw: raw_data = (base64.b64encode(packet._raw_data) if packet._raw_data else packet._raw_data) raw_append = " RAW:%r" % raw_data dhcp.get_logger().log( level, "%-12s %-8s %s 0x%08x (%s)%s", prefix, t_name, mac, xid, client_foo, raw_append, ) if raven_client and level >= raven_client_min_level or t_name == "decline": if "IGN" in prefix: if "LIMIT" in prefix: message = "request from %s ignored due to rate limiting" % mac elif "UNAVAIL" in prefix: message = "unable to find appropriate lease: giaddr=%s" % giaddr else: message = prefix[:-1] elif t_name == "decline": message = "dhcpdecline from host %s" % mac else: message = "%s %s from %s" % (prefix, t_name.upper(), mac) requested_ip = bytes_to_ip(packet, "request_ip_address") raven_client.captureMessage( message, tags={"server": packet.get_recv_interface()["address"]}, level=level, extra={ "server_ip_address": packet.get_recv_interface()["address"], "server_interface": packet.get_recv_interface(), "t_name": t_name, "mac": mac, "xid": xid, "client": client, "giaddr": giaddr, "requested_ip": requested_ip, "recvd_from": recvd_from, }, )