示例#1
0
    def test_dhcp_vlan_multi(self):
        self._setup_vlan_network()

        vlan1 = 51
        mac1 = MacAddress("11:22:33:44:55:66")
        vlan2 = 52
        mac2 = MacAddress("22:22:33:44:55:66")
        vlan3 = 53
        mac3 = MacAddress("11:22:33:44:55:66")

        self._setup_dhcp_on_vlan(vlan1)
        self._setup_dhcp_on_vlan(vlan2)
        self._setup_dhcp_on_vlan(vlan3)

        self._validate_dhcp_alloc_renew(mac1, vlan1)
        self._validate_dhcp_alloc_renew(mac2, vlan2)
        self._validate_dhcp_alloc_renew(mac3, vlan3)

        self._validate_ip_subnet(mac1, vlan1)
        self._validate_ip_subnet(mac2, vlan2)
        self._validate_ip_subnet(mac3, vlan3)

        self._release_ip(mac1, vlan1)
        self._release_ip(mac2, vlan2)
        self._release_ip(mac3, vlan3)
示例#2
0
    def test_dhcp_lease1(self):
        self._setup_sniffer()
        mac1 = MacAddress("11:22:33:44:55:66")
        dhcp1 = self._alloc_ip_address_from_dhcp(mac1)
        self.assertEqual(dhcp1.state_requested, DHCPState.REQUEST)
        assert (dhcp1.state == DHCPState.OFFER or dhcp1.state == DHCPState.ACK)

        # trigger lease reneval before deadline
        time1 = datetime.datetime.now() + datetime.timedelta(seconds=100)
        self._start_sniffer()
        with freeze_time(time1):
            time.sleep(PKT_CAPTURE_WAIT)
            self._stop_sniffer_and_check(DHCPState.REQUEST, mac1)
            self.assertEqual(dhcp1.state_requested, DHCPState.REQUEST)
            assert (dhcp1.state == DHCPState.OFFER or dhcp1.state == DHCPState.ACK)

            # trigger lease after deadline
            time2 = datetime.datetime.now() + datetime.timedelta(seconds=200)
            self._start_sniffer()
            with freeze_time(time2):
                time.sleep(PKT_CAPTURE_WAIT)
                self._stop_sniffer_and_check(DHCPState.DISCOVER, mac1)
                self.assertEqual(dhcp1.state_requested, DHCPState.REQUEST)
                assert (dhcp1.state == DHCPState.OFFER or dhcp1.state == DHCPState.ACK)

        self._dhcp_client.release_ip_address(mac1)

        dhcp1 = self.dhcp_store.get(mac1.as_redis_key())
        self.assertEqual(dhcp1.state_requested, DHCPState.RELEASE)
示例#3
0
    def send_dhcp_packet(self,
                         mac: MacAddress,
                         vlan: str,
                         state: DHCPState,
                         dhcp_desc: DHCPDescriptor = None):
        """
        Send DHCP packet and record state in dhcp_client_state.

        Args:
            mac: MAC address of interface
            state: state of DHCP packet
            dhcp_desc: DHCP protocol state.
        Returns:
        """
        ciaddr = None

        # generate DHCP request packet
        if state == DHCPState.DISCOVER:
            dhcp_opts = [("message-type", "discover")]
            dhcp_desc = DHCPDescriptor(mac=mac,
                                       ip="",
                                       vlan=vlan,
                                       state_requested=DHCPState.DISCOVER)
            self._msg_xid = self._msg_xid + 1
            pkt_xid = self._msg_xid
        elif state == DHCPState.REQUEST:
            dhcp_opts = [("message-type", "request"),
                         ("requested_addr", dhcp_desc.ip),
                         ("server_id", dhcp_desc.server_ip)]
            dhcp_desc.state_requested = DHCPState.REQUEST
            pkt_xid = dhcp_desc.xid
            ciaddr = dhcp_desc.ip
        elif state == DHCPState.RELEASE:
            dhcp_opts = [("message-type", "release"),
                         ("server_id", dhcp_desc.server_ip)]
            dhcp_desc.state_requested = DHCPState.RELEASE
            self._msg_xid = self._msg_xid + 1
            pkt_xid = self._msg_xid
            ciaddr = dhcp_desc.ip
        else:
            LOG.warning("Unknown egress request mac %s state %s", str(mac),
                        state)
            return

        dhcp_opts.append("end")
        dhcp_desc.xid = pkt_xid
        with self._dhcp_notify:
            self.dhcp_client_state[mac.as_redis_key(vlan)] = dhcp_desc

        pkt = Ether(src=str(mac), dst="ff:ff:ff:ff:ff:ff")
        if vlan and vlan != "0":
            pkt /= Dot1Q(vlan=int(vlan))
        pkt /= IP(src="0.0.0.0", dst="255.255.255.255")
        pkt /= UDP(sport=68, dport=67)
        pkt /= BOOTP(op=1, chaddr=mac.as_hex(), xid=pkt_xid, ciaddr=ciaddr)
        pkt /= DHCP(options=dhcp_opts)
        LOG.debug("DHCP pkt xmit %s", pkt.show(dump=True))

        sendp(pkt, iface=self._dhcp_interface, verbose=0)
示例#4
0
    def _process_dhcp_pkt(self, packet, state: DHCPState):
        LOG.debug("DHCP pkt recv %s", packet.show(dump=True))

        mac_addr = MacAddress(hex_to_mac(packet[BOOTP].chaddr.hex()[0:12]))
        vlan = ""
        if Dot1Q in packet:
            vlan = str(packet[Dot1Q].vlan)
        mac_addr_key = mac_addr.as_redis_key(vlan)

        with self._dhcp_notify:
            if mac_addr_key in self.dhcp_client_state:
                state_requested = self.dhcp_client_state[
                    mac_addr_key].state_requested
                if BOOTP not in packet or packet[BOOTP].yiaddr is None:
                    LOG.error("no ip offered")
                    return

                ip_offered = packet[BOOTP].yiaddr
                subnet_mask = self._get_option(packet, "subnet_mask")
                if subnet_mask is not None:
                    ip_subnet = IPv4Network(ip_offered + "/" + subnet_mask,
                                            strict=False)
                else:
                    ip_subnet = IPv4Network(ip_offered + "/" + "32",
                                            strict=False)

                dhcp_router_opt = self._get_option(packet, "router")
                if dhcp_router_opt is not None:
                    router_ip_addr = ip_address(dhcp_router_opt)
                    self.dhcp_gw_info.update_ip(router_ip_addr, vlan)
                else:
                    router_ip_addr = None

                lease_expiration_time = self._get_option(packet, "lease_time")
                dhcp_state = DHCPDescriptor(
                    mac=mac_addr,
                    ip=ip_offered,
                    state=state,
                    vlan=vlan,
                    state_requested=state_requested,
                    subnet=str(ip_subnet),
                    server_ip=packet[IP].src,
                    router_ip=router_ip_addr,
                    lease_expiration_time=lease_expiration_time,
                    xid=packet[BOOTP].xid)
                LOG.info("Record DHCP for: %s state: %s", mac_addr_key,
                         dhcp_state)

                self.dhcp_client_state[mac_addr_key] = dhcp_state
                self._dhcp_notify.notifyAll()

                if state == DHCPState.OFFER:
                    #  let other thread work on fulfilling IP allocation request.
                    threading.Event().wait(self.THREAD_YIELD_TIME)
                    self.send_dhcp_packet(mac_addr, vlan, DHCPState.REQUEST,
                                          dhcp_state)
            else:
                LOG.debug("Unknown MAC: %s " % packet.summary())
                return
示例#5
0
    def del_record(self, args):
        """
        Delete DHCP state record from the redis map.
        Args:
            args: Mac address.

        Returns: None
        """

        mac = MacAddress(args.mac)
        desc = self.dhcp_client_state[mac.as_redis_key()]
        print("Deleted mac %s with DHCP rec %s" % (str(mac), desc))
        self.dhcp_client_state[mac.as_redis_key()] = None
示例#6
0
    def release_ip_address(self, mac: MacAddress):
        """
                Release DHCP allocated IP.
        Args:
            mac: MAC address of the IP allocated.

        Returns: None
        """

        if mac.as_redis_key() not in self.dhcp_client_state:
            LOG.error("Unallocated DHCP release for MAC: %s", str(mac))
            return

        dhcp_desc = self.dhcp_client_state[mac.as_redis_key()]
        self.send_dhcp_packet(mac, DHCPState.RELEASE, dhcp_desc)
示例#7
0
    def test_dhcp_lease1(self):
        self.pkt_list_lock = threading.Condition()

        self._setup_sniffer()
        mac1 = MacAddress("11:22:33:44:55:66")
        self._alloc_ip_address_from_dhcp(mac1)
        self._validate_req_state(mac1, DHCPState.REQUEST)
        self._validate_state_as_current(mac1)

        # trigger lease reneval before deadline
        time1 = datetime.datetime.now() + datetime.timedelta(seconds=100)
        self._start_sniffer()
        with freeze_time(time1):
            self._stop_sniffer_and_check(DHCPState.REQUEST, mac1)
            self._validate_req_state(mac1, DHCPState.REQUEST)
            self._validate_state_as_current(mac1)

            # trigger lease after deadline
            time2 = datetime.datetime.now() + datetime.timedelta(seconds=200)
            self._start_sniffer()
            with freeze_time(time2):
                LOG.debug("check discover after lease loss")
                self._stop_sniffer_and_check(DHCPState.DISCOVER, mac1)
                self._validate_req_state(mac1, DHCPState.REQUEST)
                self._validate_state_as_current(mac1)

        self._dhcp_client.release_ip_address(mac1)
        time.sleep(PKT_CAPTURE_WAIT)
        self._validate_req_state(mac1, DHCPState.RELEASE)
示例#8
0
    def _validate_req_state(self, mac: MacAddress, state: DHCPState, vlan: str):
        for x in range(RETRY_LIMIT):
            LOG.debug("wait for state: %d" % x)
            with self.dhcp_wait:
                dhcp1 = self.dhcp_store.get(mac.as_redis_key(vlan))
                if dhcp1.state_requested == state:
                    return
            time.sleep(PKT_CAPTURE_WAIT)

        assert 0
示例#9
0
    def test_dhcp_vlan(self):
        vlan1: int = 2
        mac1 = MacAddress("11:22:33:44:55:66")

        self._setup_vlan_network()
        self._setup_dhcp_on_vlan(vlan1)

        self._validate_dhcp_alloc_renew(mac1, vlan1)
        self._validate_ip_subnet(mac1, vlan1)
        self._release_ip(mac1, vlan1)
示例#10
0
    def add_record(self, args):
        """
        Add DHCP record.
        Args:
            args: All data required for DHCP state.

        Returns:

        """

        state = DHCPState(args.state)
        ipaddr = ip_address(args.ip)
        subnet = ip_network(args.subnet, strict=False)
        dhcp_ip = ip_address(args.dhcp)
        desc = DHCPDescriptor(args.mac, str(ipaddr), state, subnet, dhcp_ip, None,
                              args.lease, random.randint(0, 50000))
        mac = MacAddress(args.mac)
        self.dhcp_client_state[mac.as_redis_key()] = desc
        print("Added mac %s with DHCP rec %s" % str(mac), desc)
示例#11
0
 def _validate_ip_subnet(self, mac: MacAddress, vlan: int):
     # vlan is configured with subnet : 10.200.x.1
     # router IP is 10.200.x.211
     # x is vlan id
     exptected_subnet = ipaddress.ip_network("10.200.%s.0/24" % vlan)
     exptected_router_ip = ipaddress.ip_address("10.200.%s.211" % vlan)
     with self.dhcp_wait:
         dhcp1 = self.dhcp_store.get(mac.as_redis_key(vlan))
         self.assertEqual(dhcp1.subnet, str(exptected_subnet))
         self.assertEqual(dhcp1.router_ip, exptected_router_ip)
         self.assert_(ipaddress.ip_address(dhcp1.ip) in exptected_subnet)
示例#12
0
    def get_dhcp_desc(self, mac: MacAddress) -> Optional[DHCPDescriptor]:
        """
                Get DHCP description for given MAC.
        Args:
            mac: Mac address of the client

        Returns: Current DHCP info.
        """

        key = mac.as_redis_key()
        if key in self.dhcp_client_state:
            return self.dhcp_client_state[key]

        LOG.debug("lookup error for %s", str(mac))
        return None
示例#13
0
    def get_dhcp_desc(self, mac: MacAddress, vlan: str) -> Optional[DHCPDescriptor]:
        """
                Get DHCP description for given MAC.
        Args:
            mac: Mac address of the client
            vlan: vlan id if the IP allocated in a VLAN

        Returns: Current DHCP info.
        """

        key = mac.as_redis_key(vlan)
        if key in self.dhcp_client_state:
            return self.dhcp_client_state[key]

        LOG.debug("lookup error for %s", str(key))
        return None
示例#14
0
    def release_ip_address(self, mac: MacAddress, vlan: str):
        """
                Release DHCP allocated IP.
        Args:
            mac: MAC address of the IP allocated.
            vlan: vlan id if the IP allocated in a VLAN

        Returns: None
        """
        key = mac.as_redis_key(vlan)
        if key not in self.dhcp_client_state:
            LOG.error("Unallocated DHCP release for MAC: %s", key)
            return

        dhcp_desc = self.dhcp_client_state[key]
        self.send_dhcp_packet(mac, dhcp_desc.vlan, DHCPState.RELEASE, dhcp_desc)
示例#15
0
    def test_dhcp_lease1(self):
        self._setup_dhcp_vlan_off()

        mac1 = MacAddress("11:22:33:44:55:66")
        self._validate_dhcp_alloc_renew(mac1, None)
示例#16
0
 def _validate_state_as_current(self, mac: MacAddress, vlan: int):
     with self.dhcp_wait:
         dhcp1 = self.dhcp_store.get(mac.as_redis_key(vlan))
         self.assert_(
             dhcp1.state == DHCPState.OFFER
             or dhcp1.state == DHCPState.ACK, )
示例#17
0
 def _get_state_xid(self, mac: MacAddress, vlan: int):
     with self.dhcp_wait:
         dhcp1 = self.dhcp_store.get(mac.as_redis_key(vlan))
         return dhcp1.xid
示例#18
0
 def _validate_state_as_current(self, mac: MacAddress):
     with self.dhcp_wait:
         dhcp1 = self.dhcp_store.get(mac.as_redis_key())
         assert (dhcp1.state == DHCPState.OFFER
                 or dhcp1.state == DHCPState.ACK)
示例#19
0
 def _validate_req_state(self, mac: MacAddress, state: DHCPState,
                         vlan: str):
     with self.dhcp_wait:
         dhcp1 = self.dhcp_store.get(mac.as_redis_key(vlan))
         self.assertEqual(dhcp1.state_requested, state)