def _create_test_dhcp_request_packet(self): option_list = [] bin_server = addrconv.ipv4.text_to_bin('192.168.1.1') option_list.append( dhcp.option(tag=dhcp.DHCP_SERVER_IDENTIFIER_OPT, value=bin_server)) option_list.append( dhcp.option(tag=dhcp.DHCP_MESSAGE_TYPE_OPT, value=b'\x03')) options = dhcp.options(option_list=option_list) ret_pkt = packet.Packet() ret_pkt.add_protocol( ethernet.ethernet(dst="ff:ff:ff:ff:ff:ff", src=self.port_info['mac_address'])) ret_pkt.add_protocol( ipv4.ipv4(dst="255.255.255.255", src="0.0.0.0", proto=inet.IPPROTO_UDP)) ret_pkt.add_protocol( udp.udp(src_port=constants.DHCP_CLIENT_PORT, dst_port=constants.DHCP_RESPONSE_PORT)) ret_pkt.add_protocol( dhcp.dhcp(op=dhcp.DHCP_BOOT_REQUEST, chaddr=self.port_info['mac_address'], siaddr='0.0.0.0', xid=3454038351, options=options)) return ret_pkt
def test_get_dhcp_options(self): expect_bin_routes = (b'\x00\xc0\xa8o\x01 \xa9\xfe\xa9\xfe\xc0\xa8o\x01' b'\x18\x01\x01\x01\xc0\xa8\x01d ' b'\x02\x02\x02\x02\xc0\xa8\x01e') expect_offer_options = dhcp.options( magic_cookie='99.130.83.99', option_list=[ dhcp.option(length=0, tag=53, value=b'\x02'), dhcp.option(length=0, tag=54, value=b'\xc0\xa8o\x01'), dhcp.option(length=0, tag=51, value=b'\x00\x01Q\x80'), dhcp.option(length=0, tag=1, value=b'\xff\xff\xff\x00'), dhcp.option(length=0, tag=28, value=b'\xc0\xa8o\xff'), dhcp.option(length=0, tag=6, value=b'\x08\x08\x08\x08\x08\x08\x04\x04'), dhcp.option(length=0, tag=15, value=b'openstacklocal'), dhcp.option(length=0, tag=3, value=b'\xc0\xa8o\x01'), dhcp.option(length=0, tag=121, value=expect_bin_routes), dhcp.option(length=0, tag=26, value=b'\x05\xaa') ], options_len=0) offer_options = self.dhcp4_responer.get_dhcp_options(self.port_info) self._compare_option_values(expect_offer_options.option_list, offer_options.option_list) expect_ack_options = dhcp.options( magic_cookie='99.130.83.99', option_list=[ dhcp.option(length=0, tag=53, value=b'\x05'), dhcp.option(length=0, tag=54, value=b'\xc0\xa8o\x01'), dhcp.option(length=0, tag=51, value=b'\x00\x01Q\x80'), dhcp.option(length=0, tag=1, value=b'\xff\xff\xff\x00'), dhcp.option(length=0, tag=28, value=b'\xc0\xa8o\xff'), dhcp.option(length=0, tag=6, value=b'\x08\x08\x08\x08\x08\x08\x04\x04'), dhcp.option(length=0, tag=15, value=b'openstacklocal'), dhcp.option(length=0, tag=3, value=b'\xc0\xa8o\x01'), dhcp.option(length=0, tag=121, value=expect_bin_routes), dhcp.option(length=0, tag=26, value=b'\x05\xaa') ], options_len=0) ack_options = self.dhcp4_responer.get_dhcp_options(self.port_info, is_ack=True) self._compare_option_values(expect_ack_options.option_list, ack_options.option_list)
def _send_dhcp_req_to_app(self, lport, dhcp_port, options=None): req = dhcp.dhcp(op=dhcp.DHCP_DISCOVER, chaddr='aa:aa:aa:aa:aa:aa', options=dhcp.options(options)) pkt = self._create_fake_empty_packet() dhcp_response_pkt = self.app._create_dhcp_response(pkt, req, dhcp.DHCP_OFFER, lport, dhcp_port) return dhcp_response_pkt
def _create_dhcp_response(self, packet, dhcp_request, response_type, lport, dhcp_port): pkt_ipv4 = packet.get_protocol(ipv4.ipv4) pkt_ethernet = packet.get_protocol(ethernet.ethernet) try: subnet = lport.subnets[0] except IndexError: LOG.warning("No subnet found for port %s", lport.id) return dhcp_server_address = self._dhcp_ip_by_subnet.get(subnet.id) if not dhcp_server_address: LOG.warning("Could not find DHCP server address for subnet %s", subnet.id) return option_list = self._build_dhcp_options(dhcp_request, response_type, lport, subnet, dhcp_server_address) options = dhcp.options(option_list=option_list) dhcp_response = os_ken_packet.Packet() dhcp_response.add_protocol( ethernet.ethernet(ethertype=ether.ETH_TYPE_IP, dst=pkt_ethernet.src, src=dhcp_port.mac)) dhcp_response.add_protocol( ipv4.ipv4(dst=pkt_ipv4.src, src=dhcp_server_address, proto=pkt_ipv4.proto)) dhcp_response.add_protocol( udp.udp(src_port=const.DHCP_SERVER_PORT, dst_port=const.DHCP_CLIENT_PORT)) siaddr = lport.dhcp_params.siaddr or dhcp_server_address dhcp_response.add_protocol( dhcp.dhcp(op=dhcp.DHCP_BOOT_REPLY, chaddr=pkt_ethernet.src, siaddr=siaddr, boot_file=dhcp_request.boot_file, yiaddr=lport.ip, xid=dhcp_request.xid, options=options)) return dhcp_response
def get_dhcp_options(self, port_info, is_ack=False): fixed_ips = port_info['fixed_ips'] net = netaddr.IPNetwork(fixed_ips[0]['cidr']) dns_nameservers = fixed_ips[0]['dns_nameservers'] host_routes = fixed_ips[0]['host_routes'] gateway_ip = fixed_ips[0]['gateway_ip'] bin_server = addrconv.ipv4.text_to_bin(gateway_ip) option_list = [] if is_ack: option_list.append( dhcp.option(tag=dhcp.DHCP_MESSAGE_TYPE_OPT, value=DHCPV4_MSG_TYPE_BYTES_ACK)) else: option_list.append( dhcp.option(tag=dhcp.DHCP_MESSAGE_TYPE_OPT, value=DHCPV4_MSG_TYPE_BYTES_OFFER)) option_list.append( dhcp.option(tag=dhcp.DHCP_SERVER_IDENTIFIER_OPT, value=bin_server)) option_list.append( dhcp.option(tag=dhcp.DHCP_IP_ADDR_LEASE_TIME_OPT, value=struct.pack( '!i', cfg.CONF.dhcp_lease_duration))) if cfg.CONF.DHCP.dhcp_renewal_time > 0: option_list.append( dhcp.option(tag=dhcp.DHCP_RENEWAL_TIME_OPT, value=struct.pack( '!I', cfg.CONF.DHCP.dhcp_renewal_time))) if cfg.CONF.DHCP.dhcp_rebinding_time > 0: option_list.append( dhcp.option(tag=dhcp.DHCP_REBINDING_TIME_OPT, value=struct.pack( '!I', cfg.CONF.DHCP.dhcp_rebinding_time))) option_list.append( dhcp.option(tag=dhcp.DHCP_SUBNET_MASK_OPT, value=addrconv.ipv4.text_to_bin(str(net.netmask)))) # Option: (28) Broadcast Address option_list.append( dhcp.option(tag=DHCP_BROADCAST_ADDRESS_OPT, value=addrconv.ipv4.text_to_bin(str(net.broadcast)))) # DNS if dns_nameservers: option_list.append( dhcp.option(tag=dhcp.DHCP_DNS_SERVER_ADDR_OPT, value=self.get_bin_dns(dns_nameservers))) if cfg.CONF.dns_domain: option_list.append( dhcp.option(tag=dhcp.DHCP_DOMAIN_NAME_OPT, value=struct.pack( '!%ds' % len(cfg.CONF.dns_domain), str.encode(cfg.CONF.dns_domain)))) option_list.append( dhcp.option(tag=dhcp.DHCP_GATEWAY_ADDR_OPT, value=bin_server)) # Static routes option_list.append( dhcp.option(tag=dhcp.DHCP_CLASSLESS_ROUTE_OPT, value=self.get_bin_routes(gateway_ip, host_routes))) # MTU mtu = int(port_info.get('mtu', 0)) if mtu > 0: mtu_bin = struct.pack('!H', mtu) option_list.append( dhcp.option(tag=dhcp.DHCP_INTERFACE_MTU_OPT, value=mtu_bin)) options = dhcp.options(option_list=option_list) return options
class Test_dhcp_offer(unittest.TestCase): op = dhcp.DHCP_BOOT_REPLY chaddr = 'aa:aa:aa:aa:aa:aa' htype = 1 hlen = 6 hops = 0 xid = 1 secs = 0 flags = 1 ciaddr = '192.168.10.10' yiaddr = '192.168.20.20' siaddr = '192.168.30.30' giaddr = '192.168.40.40' sname = 'abc' boot_file = '' option_list = [ dhcp.option(dhcp.DHCP_MESSAGE_TYPE_OPT, b'\x02', 1), dhcp.option(dhcp.DHCP_SUBNET_MASK_OPT, b'\xff\xff\xff\x00', 4), dhcp.option(dhcp.DHCP_GATEWAY_ADDR_OPT, b'\xc0\xa8\x0a\x09', 4), dhcp.option(dhcp.DHCP_DNS_SERVER_ADDR_OPT, b'\xc0\xa8\x0a\x09', 4), dhcp.option(dhcp.DHCP_IP_ADDR_LEASE_TIME_OPT, b'\x00\x03\xf4\x80', 4), dhcp.option(dhcp.DHCP_RENEWAL_TIME_OPT, b'\x00\x01\xfa\x40', 4), dhcp.option(dhcp.DHCP_REBINDING_TIME_OPT, b'\x00\x03\x75\xf0', 4), dhcp.option(dhcp.DHCP_SERVER_IDENTIFIER_OPT, b'\xc0\xa8\x0a\x09', 4) ] magic_cookie = '99.130.83.99' options = dhcp.options(option_list=option_list, options_len=50, magic_cookie=magic_cookie) dh = dhcp.dhcp(op, chaddr, options, htype=htype, hlen=hlen, hops=hops, xid=xid, secs=secs, flags=flags, ciaddr=ciaddr, yiaddr=yiaddr, siaddr=siaddr, giaddr=giaddr, sname=sname, boot_file=boot_file) buf = (b"\x02\x01\x06\x00\x00\x00\x00\x01\x00\x00\x00\x01\xc0\xa8\x0a\x0a" b"\xc0\xa8\x14\x14\xc0\xa8\x1e\x1e\xc0\xa8\x28\x28\xaa\xaa\xaa\xaa" b"\xaa\xaa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x61\x62\x63\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x63\x82\x53\x63" b"\x35\x01\x02\x01\x04\xff\xff\xff\x00\x03\x04\xc0\xa8\x0a\x09\x06" b"\x04\xc0\xa8\x0a\x09\x33\x04\x00\x03\xf4\x80\x3a\x04\x00\x01\xfa" b"\x40\x3b\x04\x00\x03\x75\xf0\x36\x04\xc0\xa8\x0a\x09\xff") def setUp(self): pass def tearDown(self): pass def test_init(self): eq_(self.op, self.dh.op) eq_(self.htype, self.dh.htype) eq_(self.hlen, self.dh.hlen) eq_(self.hops, self.dh.hops) eq_(self.xid, self.dh.xid) eq_(self.secs, self.dh.secs) eq_(self.flags, self.dh.flags) eq_(self.ciaddr, self.dh.ciaddr) eq_(self.yiaddr, self.dh.yiaddr) eq_(self.siaddr, self.dh.siaddr) eq_(self.giaddr, self.dh.giaddr) eq_(self.chaddr, self.dh.chaddr) eq_(self.sname, self.dh.sname) eq_(self.boot_file, self.dh.boot_file) eq_(str(self.options), str(self.dh.options)) def test_parser(self): res, _, rest = dhcp.dhcp.parser(self.buf) eq_(self.op, res.op) eq_(self.htype, res.htype) eq_(self.hlen, res.hlen) eq_(self.hops, res.hops) eq_(self.xid, res.xid) eq_(self.secs, res.secs) eq_(self.flags, res.flags) eq_(self.ciaddr, res.ciaddr) eq_(self.yiaddr, res.yiaddr) eq_(self.siaddr, res.siaddr) eq_(self.giaddr, res.giaddr) eq_(self.chaddr, res.chaddr) # sname is 64 byte length. rest of data is filled by '\x00'. eq_(self.sname.ljust(64, '\x00'), res.sname) # boof_file is 128 byte length. rest of data is filled by '\x00'. eq_(self.boot_file.ljust(128, '\x00'), res.boot_file) eq_(str(self.options), str(res.options)) eq_(b'', rest) def test_parser_corrupted(self): corrupt_buf = self.buf[:-4] pkt, _, rest = dhcp.dhcp.parser(corrupt_buf) ok_(isinstance(pkt, dhcp.dhcp)) ok_(isinstance(pkt.options, dhcp.options)) for opt in pkt.options.option_list[:-1]: ok_(isinstance(opt, dhcp.option)) ok_(isinstance(pkt.options.option_list[-1], six.binary_type)) buf = pkt.serialize() eq_(str(buf), str(corrupt_buf)) eq_(b'', rest) def test_serialize(self): buf = self.dh.serialize() res = struct.unpack_from(dhcp.dhcp._DHCP_PACK_STR, six.binary_type(buf)) eq_(self.op, res[0]) eq_(self.htype, res[1]) eq_(self.hlen, res[2]) eq_(self.hops, res[3]) eq_(self.xid, res[4]) eq_(self.secs, res[5]) eq_(self.flags, res[6]) eq_(self.ciaddr, addrconv.ipv4.bin_to_text(res[7])) eq_(self.yiaddr, addrconv.ipv4.bin_to_text(res[8])) eq_(self.siaddr, addrconv.ipv4.bin_to_text(res[9])) eq_(self.giaddr, addrconv.ipv4.bin_to_text(res[10])) eq_(self.chaddr, addrconv.mac.bin_to_text(res[11][:6])) # sname is 64 byte length. rest of data is filled by '\x00'. eq_(self.sname.ljust(64, '\x00'), res[12].decode('ascii')) # boof_file is 128 byte length. rest of data is filled by '\x00'. eq_(self.boot_file.ljust(128, '\x00'), res[13].decode('ascii')) options = dhcp.options.parser( buf[struct.calcsize(dhcp.dhcp._DHCP_PACK_STR):]) eq_(str(self.options), str(options)) def test_to_string(self): option_values = ['tag', 'length', 'value'] opt_str_list = [] for option in self.option_list: _opt_str = ','.join([ '%s=%s' % (k, repr(getattr(option, k))) for k, v in inspect.getmembers(option) if k in option_values ]) opt_str = '%s(%s)' % (dhcp.option.__name__, _opt_str) opt_str_list.append(opt_str) option_str = '[%s]' % ', '.join(opt_str_list) opts_vals = { 'magic_cookie': repr(self.magic_cookie), 'option_list': option_str, 'options_len': repr(self.options.options_len) } _options_str = ','.join([ '%s=%s' % (k, opts_vals[k]) for k, v in inspect.getmembers(self.options) if k in opts_vals ]) options_str = '%s(%s)' % (dhcp.options.__name__, _options_str) dhcp_values = { 'op': repr(self.op), 'htype': repr(self.htype), 'hlen': repr(self.hlen), 'hops': repr(self.hops), 'xid': repr(self.xid), 'secs': repr(self.secs), 'flags': repr(self.flags), 'ciaddr': repr(self.ciaddr), 'yiaddr': repr(self.yiaddr), 'siaddr': repr(self.siaddr), 'giaddr': repr(self.giaddr), 'chaddr': repr(self.chaddr), 'sname': repr(self.sname), 'boot_file': repr(self.boot_file), 'options': options_str } _dh_str = ','.join([ '%s=%s' % (k, dhcp_values[k]) for k, v in inspect.getmembers(self.dh) if k in dhcp_values ]) dh_str = '%s(%s)' % (dhcp.dhcp.__name__, _dh_str) eq_(str(self.dh), dh_str) eq_(repr(self.dh), dh_str) def test_json(self): jsondict = self.dh.to_jsondict() dh = dhcp.dhcp.from_jsondict(jsondict['dhcp']) eq_(str(self.dh), str(dh))