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)
def _process_dhcp_pkt(self, packet, state: DHCPState): mac_addr = create_mac_from_sid(packet[Ether].dst) mac_addr_key = mac_addr.as_redis_key() with self._dhcp_notify: if mac_addr_key in self.dhcp_client_state: ip_offered = packet[BOOTP].yiaddr subnet_mask = packet[DHCP].options[5][1] ip_subnet = IPv4Network(ip_offered + "/" + subnet_mask, strict=False) router_ip_addr = ip_address(packet[DHCP].options[7][1]) lease_time = packet[DHCP].options[2][1] dhcp_state = DHCPDescriptor(mac_addr, ip_offered, state, str(ip_subnet), packet[IP].src, router_ip_addr, lease_time, packet[BOOTP].xid) LOG.info("Record mac %s IP %s", mac_addr_key, dhcp_state) self.dhcp_client_state[mac_addr_key] = dhcp_state self.dhcp_gw_info.update_ip(router_ip_addr) 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, DHCPState.REQUEST, dhcp_state) else: LOG.debug("Unknown MAC: %s " % packet.summary()) return
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
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)