Example #1
0
 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
Example #2
0
    def _build_dhcp_options(self, dhcp_request, response_type, lport, subnet,
                            srv_addr):
        """
        according the RFC the server need to response with
        with all the option that "explicitly configured options"
        and supply as many of the "requested parameters" as
        possible

        https://www.ietf.org/rfc/rfc2131.txt (page 29)
         """

        # explicitly configured options
        default_opts = self._build_response_default_options(
            response_type, lport, subnet, srv_addr)

        # requested options (according to dhcp_params.opt)
        response_opts = self._build_response_requested_options(
            dhcp_request, lport, default_opts)

        response_opts.update(default_opts)

        option_list = [
            dhcp.option(tag, value) for tag, value in response_opts.items()
        ]

        return option_list
Example #3
0
    def get_ret_packet(self, packet_in, port_info, is_ack=False):
        ip_info = self.get_port_ip(port_info,
                                   ip_version=constants.IP_VERSION_4)
        if not ip_info:
            return
        ip_addr = ip_info['ip_address']
        gateway_ip = ip_info['gateway_ip']

        options = self.get_dhcp_options(port_info, is_ack)
        if is_ack:
            fqdn = 'host-%s' % ip_addr.replace('.', '-').replace(':', '-')
            if cfg.CONF.dns_domain:
                fqdn = '%s.%s' % (fqdn, cfg.CONF.dns_domain)
            domain_name_bin = struct.pack('!%ds' % len(fqdn),
                                          bytes(str(fqdn).encode()))
            options.option_list.append(
                dhcp.option(tag=dhcp.DHCP_HOST_NAME_OPT,
                            value=domain_name_bin))

        header_eth = packet_in.get_protocol(ethernet.ethernet)
        header_ipv4 = packet_in.get_protocol(ipv4.ipv4)
        header_dhcp = packet_in.get_protocol(dhcp.dhcp)

        ret_pkt = packet.Packet()
        ret_pkt.add_protocol(
            ethernet.ethernet(ethertype=header_eth.ethertype,
                              dst=header_eth.src,
                              src=self.hw_addr))
        ret_pkt.add_protocol(
            ipv4.ipv4(dst=header_ipv4.dst,
                      src=gateway_ip,
                      proto=header_ipv4.proto))
        ret_pkt.add_protocol(
            udp.udp(src_port=constants.DHCP_RESPONSE_PORT,
                    dst_port=constants.DHCP_CLIENT_PORT))
        ret_pkt.add_protocol(
            dhcp.dhcp(op=dhcp.DHCP_BOOT_REPLY,
                      chaddr=header_eth.src,
                      siaddr=gateway_ip,
                      boot_file=header_dhcp.boot_file,
                      yiaddr=ip_addr,
                      xid=header_dhcp.xid,
                      options=options))
        return ret_pkt
Example #4
0
    def _create_dhcp_reponse(self, dhcp_opts, requested):
        dhcp_port = self._create_dhcp_port()
        dhcp_params = {"opts": {} if not dhcp_opts else dhcp_opts}

        fake_lport = self._build_dhcp_test_fake_lport(dhcp_port, dhcp_params)
        requested_option_connected = ''.join([chr(x) for x in requested])

        option_list = [dhcp.option(dhcp.DHCP_PARAMETER_REQUEST_LIST_OPT,
                                   requested_option_connected,
                                   len(requested))
                       ]

        dhcp_response_pkt = self._send_dhcp_req_to_app(fake_lport,
                                                       dhcp_port,
                                                       option_list)

        dhcp_res = dhcp_response_pkt.get_protocol(dhcp.dhcp)
        self.assertTrue(dhcp_res.options)
        self.assertTrue(dhcp_res.options.option_list)

        return dhcp_res
Example #5
0
    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
Example #6
0
    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)
Example #7
0
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))