def SendDhcpPacket(self, request, response): giaddr = ".".join(map(str, request.GetOption("giaddr"))) ciaddr = ".".join(map(str, request.GetOption("ciaddr"))) yiaddr = ".".join(map(str, response.GetOption("yiaddr"))) chaddr = struct.pack(6*"B", *request.GetOption("chaddr")[0:6]) broadcast = request.GetOption("flags")[0] != 0 if (giaddr != "0.0.0.0"): self.SendDhcpPacketTo(response, giaddr, self.listen_port) elif (ciaddr != "0.0.0.0"): self.SendDhcpPacketTo(response, ciaddr, self.emit_port) elif (broadcast): self.SendDhcpPacketTo(response, "255.255.255.255", self.emit_port) else: ifconfig = interface.interface() ifindex = ifconfig.getIndex(self.ifname) ifaddr = ifconfig.getAddr(self.ifname) _rawsocket.udp_send_packet( response.EncodePacket(), type_ipv4.ipv4(ifaddr).int(), self.listen_port, type_ipv4.ipv4(yiaddr).int(), self.emit_port, chaddr, ifindex )
def SendDhcpPacket(self, request, response): giaddr = ".".join(map(str, request.GetOption("giaddr"))) ciaddr = ".".join(map(str, request.GetOption("ciaddr"))) yiaddr = ".".join(map(str, response.GetOption("yiaddr"))) chaddr = struct.pack(6 * "B", *request.GetOption("chaddr")[0:6]) broadcast = request.GetOption("flags")[0] != 0 if (giaddr != "0.0.0.0"): self.SendDhcpPacketTo(response, giaddr, self.listen_port) elif (response.IsDhcpNackPacket()): self.SendDhcpPacketTo(response, "255.255.255.255", self.emit_port) elif (ciaddr != "0.0.0.0"): self.SendDhcpPacketTo(response, ciaddr, self.emit_port) elif (broadcast): self.SendDhcpPacketTo(response, "255.255.255.255", self.emit_port) else: # unicast to yiaddr ifconfig = interface.interface() ifindex = ifconfig.getIndex(self.ifname) ifaddr = ifconfig.getAddr(self.ifname) if (ifaddr is None): ifaddr = "0.0.0.0" _rawsocket.udp_send_packet(response.EncodePacket(), type_ipv4.ipv4(ifaddr).int(), self.listen_port, type_ipv4.ipv4(yiaddr).int(), self.emit_port, chaddr, ifindex)
def extractVendorOptions(self): """ Strips out vendor-specific options from the packet, returning them separately. This function is good for scrubbing information that needs to be sent monodirectionally from the client. @rtype: tuple(4) @return: A four-tuple containing, in order, option 43 (vendor_specific_information) as a string of bytes, option 60 (vendor_class_identifier) as a string, and both option 124 (vendor_class) and option 125 (vendor_specific) as digested data: [(enterprise_number:int, data:string)] and [(enterprise_number:int, [(subopt_code:byte, data:string)])], respectively. Any unset options are presented as None. """ opt_43 = self.getOption("vendor_specific_information") opt_60 = self.getOption("vendor_class_identifier") opt_124 = self.getOption("vendor_class") opt_125 = self.getOption("vendor_specific") if opt_124: data = [] while opt_124: enterprise_number = ipv4(opt_124[:4]).int() opt_124 = opt_124[4:] payload_size = ord(opt_124[0]) payload = opt_124[1:1 + payload_size] opt_124 = opt_124[1 + payload_size:] data.append(enterprise_number, payload) opt_124 = data if opt_125: data = [] while opt_125: enterprise_number = ipv4(opt_125[:4]).int() opt_125 = opt_125[4:] payload_size = ord(opt_125[0]) payload = opt_125[1:1 + payload_size] opt_125 = opt_125[1 + payload_size:] subdata = [] while payload: subopt = ord(payload[0]) subopt_size = ord(payload[1]) subpayload = payload[2:2 + subopt_size] payload = payload[2 + subopt_size:] subdata.append(subopt, subpayload) data.append(enterprise_number, subdata) opt_125 = data self.deleteOption("vendor_specific_information") self.deleteOption("vendor_class_identifier") self.deleteOption("vendor_class") self.deleteOption("vendor_specific") return (opt_43, opt_60, opt_124, opt_125)
def _OptionsToBinary(self, parameter, value): # Transform textual data into dhcp binary data p = parameter.strip() # 1- Search for header informations or specific parameter if p == 'op' or p == 'htype': value = value.strip() if value.isdigit(): return [int(value)] try: value = DhcpNames[value.strip()] return [value] except KeyError: return [0] elif p == 'hlen' or p == 'hops': try: value = int(value) return [value] except ValueError: return [0] elif p == 'secs' or p == 'flags': try: value = ipv4(int(value)).list() except ValueError: value = [0, 0, 0, 0] return value[2:] elif p == 'xid': try: value = ipv4(int(value)).list() except ValueError: value = [0, 0, 0, 0] return value elif p == 'ciaddr' or p == 'yiaddr' or p == 'siaddr' or p == 'giaddr': try: ip = ipv4(value).list() except ValueError: ip = [0, 0, 0, 0] return ip elif p == 'chaddr': try: value = hwmac(value).list() + [0] * 10 except ValueError, TypeError: value = [0] * 16 return value
def _OptionsToBinary(self,parameter,value) : # Transform textual data into dhcp binary data p = parameter.strip() # 1- Search for header informations or specific parameter if p == 'op' or p == 'htype' : value = value.strip() if value.isdigit() : return [int(value)] try : value = DhcpNames[value.strip()] return [value] except KeyError : return [0] elif p == 'hlen' or p == 'hops' : try : value = int(value) return [value] except ValueError : return [0] elif p == 'secs' or p == 'flags' : try : value = ipv4(int(value)).list() except ValueError : value = [0,0,0,0] return value[2:] elif p == 'xid' : try : value = ipv4(int(value)).list() except ValueError : value = [0,0,0,0] return value elif p == 'ciaddr' or p == 'yiaddr' or p == 'siaddr' or p == 'giaddr' : try : ip = ipv4(value).list() except ValueError : ip = [0,0,0,0] return ip elif p == 'chaddr' : try: value = hwmac(value).list()+[0]*10 except ValueError,TypeError : value = [0]*16 return value
def __init__(self, data): """ Parses the given data and stores multiple IPv4 addresses or RFC1035-formatted strings. @type data: basestring @param data: The comma-delimited IPv4s or FQDNs to process. @raise ValueError: Both IPv4s and FQDNs were specified. """ ip_4_mode = False dns_mode = False self._value = [] for token in [tok for tok in [t.strip() for t in data.split(',')] if tok]: try: self._value += type_ipv4.ipv4(token).list() ip_4_mode = True except ValueError: self._value += _rfc1035Parse(token) dns_mode = True if ip_4_mode == dns_mode: raise ValueError("'%(data)s contains both IPv4 and DNS-based entries" % { 'data': data, }) self._value.insert(0, int(ip_4_mode))
def PrintHeaders(self): print "# Header fields\n" print "readable_dhcp_headers = {" for opt in ['op','htype','hlen','hops','xid','secs','flags', 'ciaddr','yiaddr','siaddr','giaddr','chaddr','sname','file'] : begin = DhcpFields[opt][0] end = DhcpFields[opt][0]+DhcpFields[opt][1] data = self.packet_data[begin:end] if DhcpFieldsTypes[opt] == "int" : result = str(data[0]) if DhcpFieldsTypes[opt] == "int2" : result = str(data[0]*256+data[0]) if DhcpFieldsTypes[opt] == "int4" : result = str(ipv4(data).int()) if DhcpFieldsTypes[opt] == "str" : result = strlist(data).str() if DhcpFieldsTypes[opt] == "ipv4" : result = ipv4(data).str() if DhcpFieldsTypes[opt] == "hwmac" : result = "".join(map(chr,data)) line = "\t'"+opt+"':"+str(data)+",\t# "+result print line print "\t'end':'true'}"
def PrintOptions(self): print "# Options fields" print "readable_dhcp_options = {" for opt in self.options_data.keys(): data = self.options_data[opt] result = "" optnum = DhcpOptions[opt] if DhcpOptionsTypes[optnum] == "char" : result = str(data[0]) if DhcpOptionsTypes[optnum] == "16-bits" : result = str(data[0]*256+data[0]) if DhcpOptionsTypes[optnum] == "32bits" : result = str(ipv4(data).int()) if DhcpOptionsTypes[optnum] == "string" : result = strlist(data).str() if DhcpOptionsTypes[optnum] == "ipv4" : result = ipv4(data).str() if DhcpOptionsTypes[optnum] == "ipv4+" : for i in range(0,len(data),4) : if len(data[i:i+4]) == 4 : result += ipv4(data[i:i+4]).str() + " - " line = "\t'"+opt+"':"+str(data)+",\t# "+result print line print "\t'end':'true'}"
def __init__(self, mandatory, data): """ Parses the given data and stores multiple IPv4 addresses. @type mandatory: bool @param mandatory: True if the IPv4 addresses have to be respected. @type data: basestring @param data: The comma-delimited IPv4s to process. """ self._value = [int(mandatory)] for token in [tok for tok in [t.strip() for t in data.split(',')] if tok]: self._value += type_ipv4.ipv4(token).list()
def __init__(self, values): """ Parses the given data and stores multiple IPv4 addresses associated with sub-option codes. @type values: tuple @param values: A collection of (code:int, IPv4s:string) elements. """ self._value = [] for (code, addresses) in values: self._value.append(code) for token in [tok for tok in [address.strip() for address in addresses.split(',')] if tok]: self._value += type_ipv4.ipv4(token).list()
def PrintHeaders(self): print "# Header fields\n" print "readable_dhcp_headers = {" for opt in [ "op", "htype", "hlen", "hops", "xid", "secs", "flags", "ciaddr", "yiaddr", "siaddr", "giaddr", "chaddr", "sname", "file", ]: begin = DhcpFields[opt][0] end = DhcpFields[opt][0] + DhcpFields[opt][1] data = self.packet_data[begin:end] if DhcpFieldsTypes[opt] == "int": result = str(data[0]) if DhcpFieldsTypes[opt] == "int2": result = str(data[0] * 256 + data[0]) if DhcpFieldsTypes[opt] == "int4": result = str(ipv4(data).int()) if DhcpFieldsTypes[opt] == "str": result = strlist(data).str() if DhcpFieldsTypes[opt] == "ipv4": result = ipv4(data).str() if DhcpFieldsTypes[opt] == "hwmac": result = "".join(map(chr, data)) line = "\t'" + opt + "':" + str(data) + ",\t# " + result print line print "\t'end':'true'}"
def __init__(self, isns_functions, dd_access, admin_flags, isns_security, ips): """ Sets iSNS configuration parameters. @type isns_functions: int @param isns_functions: Two bytes. @type dd_access: int @param dd_access: Two bytes. @type admin_flags: int @param admin_flags: Two bytes. @type isns_security: int @param isns_security: Four bytes. @type ips: basestring @param ips: The comma-delimited IPv4s to process. """ isns_functions = intToList(isns_functions) dd_access = intToList(dd_access) admin_flags = intToList(admin_flags) isns_security = longToList(isns_security) self._value = isns_functions + dd_access + admin_flags + isns_security for token in [tok for tok in [t.strip() for t in ips.split(',')] if tok]: self._value += type_ipv4.ipv4(token).list()
def _decode_ipv4(self, data, data_len): # spec: fixed_len: 4, min_len: 4, multiplicator: 0 if len(data) == 4 and data_len == 4: return ipv4(data) return None
# 2- Search for options try : option_type = DhcpOptionsTypes[DhcpOptions[parameter]] except KeyError : return False if option_type == "ipv4" : # this is a single ip address try : binary_value = map(int,value.split(".")) except ValueError : return False elif option_type == "ipv4+" : # this is multiple ip address iplist = value.split(",") opt = [] for single in iplist : opt += (ipv4(single).list()) binary_value = opt elif option_type == "32-bits" : # This is probably a number... try : digit = int(value) binary_value = [digit>>24&0xFF,(digit>>16)&0xFF,(digit>>8)&0xFF,digit&0xFF] except ValueError : return False elif option_type == "16-bits" : try : digit = int(value) binary_value = [(digit>>8)&0xFF,digit&0xFF] except ValueError : return False
def str(self): # Process headers : printable_data = "# Header fields\n" op = self.packet_data[DhcpFields['op'][0]:DhcpFields['op'][0]+DhcpFields['op'][1]] printable_data += "op : " + DhcpFieldsName['op'][str(op[0])] + "\n" for opt in ['htype','hlen','hops','xid','secs','flags', 'ciaddr','yiaddr','siaddr','giaddr','chaddr','sname','file'] : begin = DhcpFields[opt][0] end = DhcpFields[opt][0]+DhcpFields[opt][1] data = self.packet_data[begin:end] result = '' if DhcpFieldsTypes[opt] == "int" : result = str(data[0]) elif DhcpFieldsTypes[opt] == "int2" : result = str(data[0]*256+data[1]) elif DhcpFieldsTypes[opt] == "int4" : result = str(ipv4(data).int()) elif DhcpFieldsTypes[opt] == "str" : for each in data : if each != 0 : result += chr(each) else : break elif DhcpFieldsTypes[opt] == "ipv4" : result = ipv4(data).str() elif DhcpFieldsTypes[opt] == "hwmac" : result = [] hexsym = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'] for iterator in range(6) : result += [str(hexsym[data[iterator]/16]+hexsym[data[iterator]%16])] result = ':'.join(result) printable_data += opt+" : "+result + "\n" # Process options : printable_data += "# Options fields\n" for opt in self.options_data.keys(): data = self.options_data[opt] result = "" optnum = DhcpOptions[opt] if opt=='dhcp_message_type' : result = DhcpFieldsName['dhcp_message_type'][str(data[0])] elif DhcpOptionsTypes[optnum] == "char" : result = str(data[0]) elif DhcpOptionsTypes[optnum] == "16-bits" : result = str(data[0]*256+data[0]) elif DhcpOptionsTypes[optnum] == "32-bits" : result = str(ipv4(data).int()) elif DhcpOptionsTypes[optnum] == "string" : for each in data : if each != 0 : result += chr(each) else : break elif DhcpOptionsTypes[optnum] == "ipv4" : result = ipv4(data).str() elif DhcpOptionsTypes[optnum] == "ipv4+" : for i in range(0,len(data),4) : if len(data[i:i+4]) == 4 : result += ipv4(data[i:i+4]).str() + " - " elif DhcpOptionsTypes[optnum] == "char+" : if optnum == 55 : # parameter_request_list result = ','.join([DhcpOptionsList[each] for each in data]) else : result += str(data) printable_data += opt + " : " + result + "\n" return printable_data
def __str__(self): """ Renders this packet's data in human-readable form. @rtype: str @return: A human-readable summary of this packet. """ output = ['#Header fields'] op = self._packet_data[DHCP_FIELDS['op'][0]:DHCP_FIELDS['op'][0] + DHCP_FIELDS['op'][1]] output.append("op: %(type)s" % { 'type': DHCP_FIELDS_NAMES['op'][op[0]], }) for opt in ( 'htype','hlen','hops','xid','secs','flags', 'ciaddr','yiaddr','siaddr','giaddr','chaddr', 'sname','file', ): begin = DHCP_FIELDS[opt][0] end = DHCP_FIELDS[opt][0] + DHCP_FIELDS[opt][1] data = self._packet_data[begin:end] result = None if DHCP_FIELDS_TYPES[opt] == "byte": result = str(data[0]) elif DHCP_FIELDS_TYPES[opt] == "16-bits": result = str(data[0] * 256 + data[1]) elif DHCP_FIELDS_TYPES[opt] == "32-bits": result = str(ipv4(data).int()) elif DHCP_FIELDS_TYPES[opt] == "string": result = [] for c in data: if c: result.append(chr(c)) else: break result = ''.join(result) elif DHCP_FIELDS_TYPES[opt] == "ipv4": result = ipv4(data).str() elif DHCP_FIELDS_TYPES[opt] == "hwmac": result = [] hexsym = ('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',) for iterator in xrange(6): result.append(str(hexsym[data[iterator] / 16] + hexsym[data[iterator] % 16])) result = ':'.join(result) output.append("%(opt)s: %(result)s" % { 'opt': opt, 'result': result, }) output.append('') output.append("#Options fields") for opt in self._options_data.keys(): data = self._options_data[opt] result = None optnum = DHCP_OPTIONS[opt] if opt == 'dhcp_message_type': result = DHCP_FIELDS_NAMES['dhcp_message_type'][data[0]] elif DHCP_OPTIONS_TYPES[optnum] in ("byte", "byte+", "string"): result = str(data) elif DHCP_OPTIONS_TYPES[optnum] in ("char", "char+"): if optnum == 55: # parameter_request_list requested_options = [] for d in data: requested_options.append(DHCP_OPTIONS_REVERSE[int(d)]) result = ', '.join(requested_options) else: result = [] for c in data: if 32 <= c <= 126: result.append(chr(c)) else: result.append(str(c)) result = ', '.join(result) elif DHCP_OPTIONS_TYPES[optnum] in ("16-bits", "16-bits+"): result = [] for i in xrange(0, len(data), 2): result.append(str(data[i] * 256 + data[i + 1])) result = ', '.join(result) elif DHCP_OPTIONS_TYPES[optnum] in ("32-bits", "32-bits+"): result = [] for i in xrange(0, len(data), 4): result.append(str(ipv4(data[i:i+4]).int())) result = ', '.join(result) elif DHCP_OPTIONS_TYPES[optnum] in ("ipv4", "ipv4+", "ipv4*"): result = [] for i in xrange(0, len(data), 4): result.append(ipv4(data[i:i+4]).str()) result = ', '.join(result) else: result = str(data) output.append("%(opt)s: %(result)s" % { 'opt': opt, 'result': result, }) return '\n'.join(output)
except KeyError: return False if option_type == "ipv4": # this is a single ip address try: binary_value = map(int, value.split(".")) except ValueError: return False elif option_type == "ipv4+": # this is multiple ip address iplist = value.split(",") opt = [] for single in iplist: opt += (ipv4(single).list()) binary_value = opt elif option_type == "32-bits": # This is probably a number... try: digit = int(value) binary_value = [ digit >> 24 & 0xFF, (digit >> 16) & 0xFF, (digit >> 8) & 0xFF, digit & 0xFF ] except ValueError: return False elif option_type == "16-bits": try:
def _OptionsToBinary(self, parameter, value): # Transform textual data into dhcp binary data p = parameter.strip() # 1- Search for header informations or specific parameter if p == 'op' or p == 'htype': value = value.strip() if value.isdigit(): return [int(value)] try: value = DhcpNames[value.strip()] return [value] except KeyError: return [0] elif p == 'hlen' or p == 'hops': try: value = int(value) return [value] except ValueError: return [0] elif p == 'secs' or p == 'flags': try: value = ipv4(int(value)).list() except ValueError: value = [0, 0, 0, 0] return value[2:] elif p == 'xid': try: value = ipv4(int(value)).list() except ValueError: value = [0, 0, 0, 0] return value elif p == 'ciaddr' or p == 'yiaddr' or p == 'siaddr' or p == 'giaddr': try: ip = ipv4(value).list() except ValueError: ip = [0, 0, 0, 0] return ip elif p == 'chaddr': try: value = hwmac(value).list() + [0] * 10 except (ValueError, TypeError): value = [0] * 16 return value elif p == 'sname': return elif p == 'file': return elif p == 'parameter_request_list': value = value.strip().split(',') tmp = [] for each in value: if DhcpOptions.has_key(each): tmp.append(DhcpOptions[each]) return tmp elif p == 'dhcp_message_type': try: return [DhcpNames[value]] except KeyError: return # 2- Search for options try: option_type = DhcpOptionsTypes[DhcpOptions[parameter]] except KeyError: return False if option_type == "ipv4": # this is a single ip address try: binary_value = map(int, value.split(".")) except ValueError: return False elif option_type == "ipv4+": # this is multiple ip address iplist = value.split(",") opt = [] for single in iplist: opt += (ipv4(single).list()) binary_value = opt elif option_type == "32-bits": # This is probably a number... try: digit = int(value) binary_value = [ digit >> 24 & 0xFF, (digit >> 16) & 0xFF, (digit >> 8) & 0xFF, digit & 0xFF ] except ValueError: return False elif option_type == "16-bits": try: digit = int(value) binary_value = [(digit >> 8) & 0xFF, digit & 0xFF] except ValueError: return False elif option_type == "char": try: digit = int(value) binary_value = [digit & 0xFF] except ValueError: return False elif option_type == "bool": if value == "False" or value == "false" or value == 0: binary_value = [0] else: binary_value = [1] elif option_type == "string": binary_value = strlist(value).list() else: binary_value = strlist(value).list() return binary_value
def str(self): # Process headers : printable_data = "# Header fields\n" op = self.packet_data[DhcpFields['op'][0]:DhcpFields['op'][0] + DhcpFields['op'][1]] printable_data += "op : " + DhcpFieldsName['op'][str(op[0])] + "\n" for opt in [ 'htype', 'hlen', 'hops', 'xid', 'secs', 'flags', 'ciaddr', 'yiaddr', 'siaddr', 'giaddr', 'chaddr', 'sname', 'file' ]: begin = DhcpFields[opt][0] end = DhcpFields[opt][0] + DhcpFields[opt][1] data = self.packet_data[begin:end] result = '' if DhcpFieldsTypes[opt] == "int": result = str(data[0]) elif DhcpFieldsTypes[opt] == "int2": result = str(data[0] * 256 + data[1]) elif DhcpFieldsTypes[opt] == "int4": result = str(ipv4(data).int()) elif DhcpFieldsTypes[opt] == "str": for each in data: if each != 0: result += chr(each) else: break elif DhcpFieldsTypes[opt] == "ipv4": result = ipv4(data).str() elif DhcpFieldsTypes[opt] == "hwmac": result = [] hexsym = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' ] for iterator in range(6): result += [ str(hexsym[data[iterator] / 16] + hexsym[data[iterator] % 16]) ] result = ':'.join(result) printable_data += opt + " : " + result + "\n" # Process options : printable_data += "# Options fields\n" for opt in self.options_data.keys(): data = self.options_data[opt] result = "" optnum = DhcpOptions[opt] if opt == 'dhcp_message_type': result = DhcpFieldsName['dhcp_message_type'][str(data[0])] elif DhcpOptionsTypes[optnum] == "char": result = str(data[0]) elif DhcpOptionsTypes[optnum] == "16-bits": result = str(data[0] * 256 + data[0]) elif DhcpOptionsTypes[optnum] == "32-bits": result = str(ipv4(data).int()) elif DhcpOptionsTypes[optnum] == "string": for each in data: if each != 0: result += chr(each) else: break elif DhcpOptionsTypes[optnum] == "ipv4": result = ipv4(data).str() elif DhcpOptionsTypes[optnum] == "ipv4+": for i in range(0, len(data), 4): if len(data[i:i + 4]) == 4: result += ipv4(data[i:i + 4]).str() + " - " elif DhcpOptionsTypes[optnum] == "char+": if optnum == 55: # parameter_request_list result = ','.join([DhcpOptionsList[each] for each in data]) else: result += str(data) printable_data += opt + " : " + result + "\n" return printable_data
def _decode_32_bits(self, data, data_len): if len(data) != 4: return None val = int(ipv4(data)) return data