def _icmp_packetin_handler(self): conn = self._connection ofdef = self._connection.openflowdef l3input = self.parent._gettableindex("l3input",self._connection.protocol.vhost) transactid = uint16.create(os.urandom(2)) def send_packet_out(portid,packet): for m in self.execute_commands(conn, [ ofdef.ofp_packet_out( buffer_id = ofdef.OFP_NO_BUFFER, in_port = ofdef.OFPP_CONTROLLER, actions = [ ofdef.ofp_action_output(port = portid, max_len = ofdef.OFPCML_NO_BUFFER ) ], data = packet._tobytes() ) ]): yield m icmp_packetin_matcher = OpenflowAsyncMessageEvent.createMatcher(ofdef.OFPT_PACKET_IN,None,None,l3input,2, self._connection,self._connection.connmark) while True: yield (icmp_packetin_matcher,) msg = self.event.message inport = ofdef.ofp_port_no.create(ofdef.get_oxm(msg.match.oxm_fields,ofdef.OXM_OF_IN_PORT)) # it must be icmp packet ... icmp_packet = ethernet_l7.create(msg.data) transactid = (transactid + 1) & 0xffff reply_packet = ip4_packet_l7((ip4_payload,ip4_icmp_payload), (icmp_bestparse, icmp_echo), dl_src = icmp_packet.dl_dst, dl_dst = icmp_packet.dl_src, ip_src = icmp_packet.ip_dst, ip_dst = icmp_packet.ip_src, frag_off = icmp_packet.frag_off, ttl = 128, identifier = transactid, icmp_type = ICMP_ECHOREPLY, icmp_code = icmp_packet.icmp_code, icmp_id = icmp_packet.icmp_id, icmp_seq = icmp_packet.icmp_seq, data = icmp_packet.data ) self.subroutine(send_packet_out(inport,reply_packet))
def _dhcp_handler(self): conn = self._connection ofdef = self._connection.openflowdef l3 = self._parent._gettableindex('l3input', self._connection.protocol.vhost) dhcp_packet_matcher = OpenflowAsyncMessageEvent.createMatcher( ofdef.OFPT_PACKET_IN, None, None, l3, 1, self._connection, self._connection.connmark) required_tags = [ d.OPTION_MESSAGE_TYPE, d.OPTION_SERVER_IDENTIFIER, d.OPTION_NETMASK, d.OPTION_ROUTER, d.OPTION_DNSSERVER, d.OPTION_BROADCAST, d.OPTION_MTU, d.OPTION_LEASE_TIME, d.OPTION_T1, d.OPTION_T2 ] server_mac = mac_addr(self._parent.servermac) trans_id = uint16.create(os.urandom(2)) def set_options(payload, option_dict, provide_options, message_type, remove_lease=False): message_type_opt = d.dhcp_option_message_type(value=message_type) if d.OPTION_REQUESTED_OPTIONS in option_dict: reqs = set(option_dict[d.OPTION_REQUESTED_OPTIONS].value) send_tags = [t for t in option_dict[d.OPTION_REQUESTED_OPTIONS].value if t == d.OPTION_MESSAGE_TYPE or t in provide_options] \ + [t for t in required_tags if (t in provide_options or t == d.OPTION_MESSAGE_TYPE) and t not in reqs] \ + [t for t in provide_options if t not in reqs and t not in required_tags] else: send_tags = [t for t in required_tags if t in provide_options or t == d.OPTION_MESSAGE_TYPE] \ + [t for t in set(provide_options.keys()).difference(required_tags)] d.build_options( payload, [ message_type_opt if t == d.OPTION_MESSAGE_TYPE else provide_options[t] for t in send_tags if not remove_lease or (t != d.OPTION_LEASE_TIME and t != d.OPTION_T1 and t != OPTION_T2) ], max(min(option_dict[d.OPTION_MAX_MESSAGE_SIZE].value, 1400), 576) if d.OPTION_MAX_MESSAGE_SIZE in option_dict else 576) def send_packet(pid, packet): for m in self.execute_commands(conn, [ ofdef.ofp_packet_out( buffer_id=ofdef.OFP_NO_BUFFER, in_port=ofdef.OFPP_CONTROLLER, actions=[ ofdef.ofp_action_output( port=pid, max_len=ofdef.OFPCML_NO_BUFFER) ], data=packet._tobytes()) ]): yield m while True: yield (dhcp_packet_matcher, ) msg = self.event.message try: in_port = ofdef.ofp_port_no.create( ofdef.get_oxm(msg.match.oxm_fields, ofdef.OXM_OF_IN_PORT)) if in_port not in self._dhcpentries: continue port_mac, port_ip, server_ip, provide_options = self._dhcpentries[ in_port] l7_packet = ethernet_l7.create(msg.data) dhcp_packet = d.dhcp_payload.create(l7_packet.data) if dhcp_packet.op != d.BOOTREQUEST or \ dhcp_packet.hlen != 6 or dhcp_packet.htype != 1 or \ dhcp_packet.magic_cookie != d.BOOTP_MAGIC_COOKIE or \ dhcp_packet.giaddr != 0: raise ValueError('Unsupported DHCP packet') options = d.reassemble_options(dhcp_packet) option_dict = dict((o.tag, o) for o in options) if d.OPTION_MESSAGE_TYPE not in option_dict: raise ValueError('Message type not found') message_type = option_dict[d.OPTION_MESSAGE_TYPE].value is_nak = False if message_type == d.DHCPDISCOVER: if dhcp_packet.chaddr[:6].ljust( 6, b'\x00') != mac_addr.tobytes(port_mac): # Ignore this packet continue dhcp_reply = d.dhcp_payload( op=d.BOOTREPLY, htype=1, hlen=6, hops=0, xid=dhcp_packet.xid, secs=0, flags=dhcp_packet.flags, ciaddr=0, yiaddr=port_ip, siaddr=0, giaddr=dhcp_packet.giaddr, chaddr=dhcp_packet.chaddr, magic_cookie=d.BOOTP_MAGIC_COOKIE) set_options(dhcp_reply, option_dict, provide_options, d.DHCPOFFER) elif message_type == d.DHCPREQUEST: if d.OPTION_SERVER_IDENTIFIER in option_dict and option_dict[ d.OPTION_SERVER_IDENTIFIER].value != server_ip: # Ignore packets to wrong address continue if dhcp_packet.chaddr[:6].ljust(6, b'\x00') != mac_addr.tobytes(port_mac) \ or (d.OPTION_REQUESTED_IP in option_dict and option_dict[d.OPTION_REQUESTED_IP].value != port_ip) \ or (dhcp_packet.ciaddr != 0 and dhcp_packet.ciaddr != port_ip): dhcp_reply = d.dhcp_payload( op=d.BOOTREPLY, htype=1, hlen=6, hops=0, xid=dhcp_packet.xid, secs=0, flags=dhcp_packet.flags, ciaddr=0, yiaddr=0, siaddr=0, giaddr=dhcp_packet.giaddr, chaddr=dhcp_packet.chaddr, magic_cookie=d.BOOTP_MAGIC_COOKIE) d.build_options(dhcp_reply, [ d.dhcp_option_message_type(value=d.DHCPNAK), d.dhcp_option_address( tag=d.OPTION_SERVER_IDENTIFIER, value=server_ip) ], 576, 0) is_nak = True else: dhcp_reply = d.dhcp_payload( op=d.BOOTREPLY, htype=1, hlen=6, hops=0, xid=dhcp_packet.xid, secs=0, flags=dhcp_packet.flags, ciaddr=dhcp_packet.ciaddr, yiaddr=port_ip, siaddr=0, giaddr=dhcp_packet.giaddr, chaddr=dhcp_packet.chaddr, magic_cookie=d.BOOTP_MAGIC_COOKIE) set_options(dhcp_reply, option_dict, provide_options, d.DHCPACK) elif message_type == d.DHCPDECLINE: self._logger.warning('DHCP client reports DHCPDECLINE, there should be some problems.'\ ' Connection = %r(%016x), port = %d.', self._connection, self._connection.openflow_datapathid) elif message_type == d.DHCPRELEASE: # Safe to ignore continue elif message_type == d.DHCPINFORM: dhcp_reply = d.dhcp_payload( op=d.BOOTREPLY, htype=1, hlen=6, hops=0, xid=dhcp_packet.xid, secs=0, flags=dhcp_packet.flags, ciaddr=dhcp_packet.ciaddr, yiaddr=0, siaddr=0, giaddr=dhcp_packet.giaddr, chaddr=dhcp_packet.chaddr, magic_cookie=d.BOOTP_MAGIC_COOKIE) set_options(dhcp_reply, option_dict, provide_options, d.DHCPACK, True) trans_id = (trans_id + 1) & 0xffff if (dhcp_packet.flags & d.DHCPFLAG_BROADCAST) or is_nak: dl_dst = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff] ip_dst = 0xffffffff else: dl_dst = l7_packet.dl_src ip_dst = port_ip reply_packet = ip4_packet_l7((ip4_payload, ip4_udp_payload), dl_src=server_mac, dl_dst=dl_dst, identifier=trans_id, ttl=128, ip_src=server_ip, ip_dst=ip_dst, sport=67, dport=68, data=dhcp_reply._tobytes()) self.subroutine(send_packet(in_port, reply_packet), True) except Exception: self._logger.info('Invalid DHCP packet received: %r', msg.data, exc_info=True)
async def _dhcp_handler(self): """ Mini DHCP server, respond DHCP packets from OpenFlow """ conn = self._connection ofdef = self._connection.openflowdef l3 = self._parent._gettableindex('l3input', self._connection.protocol.vhost) dhcp_packet_matcher = OpenflowAsyncMessageEvent.createMatcher( ofdef.OFPT_PACKET_IN, None, None, l3, 1, self._connection, self._connection.connmark) # These tags are important options. They are sent first to make sure the client # correctly receive these options. required_tags = [ d.OPTION_MESSAGE_TYPE, d.OPTION_SERVER_IDENTIFIER, d.OPTION_NETMASK, d.OPTION_ROUTER, d.OPTION_DNSSERVER, d.OPTION_BROADCAST, d.OPTION_MTU, d.OPTION_LEASE_TIME, d.OPTION_T1, d.OPTION_T2 ] server_mac = mac_addr(self._parent.servermac) # IP fragment identifier trans_id = uint16.create(os.urandom(2)) def set_options(payload, option_dict, provide_options, message_type, remove_lease=False): """ Set DHCP options to output payload regarding the incoming request :param payload: output DHCP payload :param option_dict: incoming DHCP options in request :param provide_options: all DHCP options that are ready to sent to the client :param message_type: output DHCP message type :param remove_lease: remove all leases options. DHCPINFORM cannot contain leases options. See https://tools.ietf.org/html/rfc2131#section-3.4 """ message_type_opt = d.dhcp_option_message_type(value=message_type) if d.OPTION_REQUESTED_OPTIONS in option_dict: # First requested options, then required options, then others reqs = set(option_dict[d.OPTION_REQUESTED_OPTIONS].value) send_tags = [t for t in option_dict[d.OPTION_REQUESTED_OPTIONS].value if t == d.OPTION_MESSAGE_TYPE or t in provide_options] \ + [t for t in required_tags if (t in provide_options or t == d.OPTION_MESSAGE_TYPE) and t not in reqs] \ + [t for t in provide_options if t not in reqs and t not in required_tags] else: # Required options, then others send_tags = [t for t in required_tags if t in provide_options or t == d.OPTION_MESSAGE_TYPE] \ + [t for t in set(provide_options.keys()).difference(required_tags)] # If the client has sent an option for max message size, use it; or use the RFC required 576 bytes not_finished = d.build_options( payload, [ message_type_opt if t == d.OPTION_MESSAGE_TYPE else provide_options[t] for t in send_tags if not remove_lease or (t != d.OPTION_LEASE_TIME and t != d.OPTION_T1 and t != OPTION_T2) ], max(min(option_dict[d.OPTION_MAX_MESSAGE_SIZE].value, 1400), 576) if d.OPTION_MAX_MESSAGE_SIZE in option_dict else 576) async def send_packet(pid, packet): """ Send DHCP packet to specified port """ await self.execute_commands(conn, [ ofdef.ofp_packet_out(buffer_id=ofdef.OFP_NO_BUFFER, in_port=ofdef.OFPP_CONTROLLER, actions=[ ofdef.ofp_action_output( port=pid, max_len=ofdef.OFPCML_NO_BUFFER) ], data=packet._tobytes()) ]) while True: ev = await dhcp_packet_matcher msg = ev.message try: in_port = ofdef.ofp_port_no.create( ofdef.get_oxm(msg.match.oxm_fields, ofdef.OXM_OF_IN_PORT)) if in_port not in self._dhcpentries: # Not a DHCP-enabled port continue port_mac, port_ip, server_ip, provide_options = self._dhcpentries[ in_port] # Fragmented DHCP packets are not supported - this is allowed according # to RFC: server and clients are only needed to support at least 576 bytes # DHCP messages. l7_packet = ethernet_l7.create(msg.data) dhcp_packet = d.dhcp_payload.create(l7_packet.data) # We only process a DHCP request directly sent from the logical port if (dhcp_packet.op != d.BOOTREQUEST # A DHCP server packet or dhcp_packet.hlen != 6 or dhcp_packet.htype != 1 # Hardware address not ethernet (48-bit) or dhcp_packet.magic_cookie != d.BOOTP_MAGIC_COOKIE # Magic cookie not match or dhcp_packet.giaddr != 0): # A relayed DHCP message raise ValueError('Unsupported DHCP packet') # Reassemble DHCP options options = d.reassemble_options(dhcp_packet) option_dict = dict((o.tag, o) for o in options) if d.OPTION_MESSAGE_TYPE not in option_dict: raise ValueError('Message type not found') message_type = option_dict[d.OPTION_MESSAGE_TYPE].value is_nak = False if message_type == d.DHCPDISCOVER: # A DHCPDISCOVER should get a DHCPOFFER response if dhcp_packet.chaddr[:6].ljust( 6, b'\x00') != mac_addr.tobytes(port_mac): # MAC address not match, ignore this packet continue dhcp_reply = d.dhcp_payload( op=d.BOOTREPLY, htype=1, hlen=6, hops=0, xid=dhcp_packet.xid, secs=0, flags=dhcp_packet.flags, ciaddr=0, yiaddr=port_ip, siaddr=0, giaddr=dhcp_packet.giaddr, chaddr=dhcp_packet.chaddr, magic_cookie=d.BOOTP_MAGIC_COOKIE) set_options(dhcp_reply, option_dict, provide_options, d.DHCPOFFER) elif message_type == d.DHCPREQUEST: # A DHCPREQUEST should get a DHCPACK reply if d.OPTION_SERVER_IDENTIFIER in option_dict and option_dict[ d.OPTION_SERVER_IDENTIFIER].value != server_ip: # Ignore packets to wrong address continue if dhcp_packet.chaddr[:6].ljust(6, b'\x00') != mac_addr.tobytes(port_mac) \ or (d.OPTION_REQUESTED_IP in option_dict and option_dict[d.OPTION_REQUESTED_IP].value != port_ip) \ or (dhcp_packet.ciaddr != 0 and dhcp_packet.ciaddr != port_ip): # Requested MAC or IP not matched, send a NACK dhcp_reply = d.dhcp_payload( op=d.BOOTREPLY, htype=1, hlen=6, hops=0, xid=dhcp_packet.xid, secs=0, flags=dhcp_packet.flags, ciaddr=0, yiaddr=0, siaddr=0, giaddr=dhcp_packet.giaddr, chaddr=dhcp_packet.chaddr, magic_cookie=d.BOOTP_MAGIC_COOKIE) # Do not send more options in NACK d.build_options(dhcp_reply, [ d.dhcp_option_message_type(value=d.DHCPNAK), d.dhcp_option_address( tag=d.OPTION_SERVER_IDENTIFIER, value=server_ip) ], 576, 0) is_nak = True else: dhcp_reply = d.dhcp_payload( op=d.BOOTREPLY, htype=1, hlen=6, hops=0, xid=dhcp_packet.xid, secs=0, flags=dhcp_packet.flags, ciaddr=dhcp_packet.ciaddr, yiaddr=port_ip, siaddr=0, giaddr=dhcp_packet.giaddr, chaddr=dhcp_packet.chaddr, magic_cookie=d.BOOTP_MAGIC_COOKIE) set_options(dhcp_reply, option_dict, provide_options, d.DHCPACK) elif message_type == d.DHCPDECLINE: # Address already in use? self._logger.warning('DHCP client reports DHCPDECLINE, there should be some problems.'\ ' Connection = %r(%016x), port = %d.', self._connection, self._connection.openflow_datapathid) elif message_type == d.DHCPRELEASE: # Safe to ignore, we do not use a dynamic IP address pool continue elif message_type == d.DHCPINFORM: # Client setup IP addresses itself, but requesting more information # DHCPINFORM reply cannot have lease options, and yiaddr = 0 dhcp_reply = d.dhcp_payload( op=d.BOOTREPLY, htype=1, hlen=6, hops=0, xid=dhcp_packet.xid, secs=0, flags=dhcp_packet.flags, ciaddr=dhcp_packet.ciaddr, yiaddr=0, siaddr=0, giaddr=dhcp_packet.giaddr, chaddr=dhcp_packet.chaddr, magic_cookie=d.BOOTP_MAGIC_COOKIE) set_options(dhcp_reply, option_dict, provide_options, d.DHCPACK, True) trans_id = (trans_id + 1) & 0xffff if (dhcp_packet.flags & d.DHCPFLAG_BROADCAST) or is_nak: # client request broadcast, or DHCPNAK # RFC requires that DHCPNAK uses broadcast dl_dst = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff] ip_dst = 0xffffffff else: dl_dst = l7_packet.dl_src ip_dst = port_ip reply_packet = ip4_packet_l7((ip4_payload, ip4_udp_payload), dl_src=server_mac, dl_dst=dl_dst, identifier=trans_id, ttl=128, ip_src=server_ip, ip_dst=ip_dst, sport=67, dport=68, data=dhcp_reply._tobytes()) # Send packet to the incoming port self.subroutine(send_packet(in_port, reply_packet), True) except Exception: self._logger.info('Invalid DHCP packet received: %r', msg.data, exc_info=True)
def _dhcp_handler(self): conn = self._connection ofdef = self._connection.openflowdef l3 = self._parent._gettableindex('l3input', self._connection.protocol.vhost) dhcp_packet_matcher = OpenflowAsyncMessageEvent.createMatcher(ofdef.OFPT_PACKET_IN, None, None, l3, 1, self._connection, self._connection.connmark) required_tags = [d.OPTION_MESSAGE_TYPE, d.OPTION_SERVER_IDENTIFIER, d.OPTION_NETMASK, d.OPTION_ROUTER, d.OPTION_DNSSERVER, d.OPTION_BROADCAST, d.OPTION_MTU, d.OPTION_LEASE_TIME, d.OPTION_T1, d.OPTION_T2] server_mac = mac_addr(self._parent.servermac) trans_id = uint16.create(os.urandom(2)) def set_options(payload, option_dict, provide_options, message_type, remove_lease = False): message_type_opt = d.dhcp_option_message_type(value = message_type) if d.OPTION_REQUESTED_OPTIONS in option_dict: reqs = set(option_dict[d.OPTION_REQUESTED_OPTIONS].value) send_tags = [t for t in option_dict[d.OPTION_REQUESTED_OPTIONS].value if t == d.OPTION_MESSAGE_TYPE or t in provide_options] \ + [t for t in required_tags if (t in provide_options or t == d.OPTION_MESSAGE_TYPE) and t not in reqs] \ + [t for t in provide_options if t not in reqs and t not in required_tags] else: send_tags = [t for t in required_tags if t in provide_options or t == d.OPTION_MESSAGE_TYPE] \ + [t for t in set(provide_options.keys()).difference(required_tags)] d.build_options(payload, [message_type_opt if t == d.OPTION_MESSAGE_TYPE else provide_options[t] for t in send_tags if not remove_lease or (t != d.OPTION_LEASE_TIME and t != d.OPTION_T1 and t != OPTION_T2)], max(min(option_dict[d.OPTION_MAX_MESSAGE_SIZE].value, 1400), 576) if d.OPTION_MAX_MESSAGE_SIZE in option_dict else 576) def send_packet(pid, packet): for m in self.execute_commands(conn, [ofdef.ofp_packet_out( buffer_id = ofdef.OFP_NO_BUFFER, in_port = ofdef.OFPP_CONTROLLER, actions = [ofdef.ofp_action_output(port = pid, max_len = ofdef.OFPCML_NO_BUFFER)], data = packet._tobytes() )]): yield m while True: yield (dhcp_packet_matcher,) msg = self.event.message try: in_port = ofdef.ofp_port_no.create(ofdef.get_oxm(msg.match.oxm_fields, ofdef.OXM_OF_IN_PORT)) if in_port not in self._dhcpentries: continue port_mac, port_ip, server_ip, provide_options = self._dhcpentries[in_port] l7_packet = ethernet_l7.create(msg.data) dhcp_packet = d.dhcp_payload.create(l7_packet.data) if dhcp_packet.op != d.BOOTREQUEST or \ dhcp_packet.hlen != 6 or dhcp_packet.htype != 1 or \ dhcp_packet.magic_cookie != d.BOOTP_MAGIC_COOKIE or \ dhcp_packet.giaddr != 0: raise ValueError('Unsupported DHCP packet') options = d.reassemble_options(dhcp_packet) option_dict = dict((o.tag, o) for o in options) if d.OPTION_MESSAGE_TYPE not in option_dict: raise ValueError('Message type not found') message_type = option_dict[d.OPTION_MESSAGE_TYPE].value is_nak = False if message_type == d.DHCPDISCOVER: if dhcp_packet.chaddr[:6].ljust(6, b'\x00') != mac_addr.tobytes(port_mac): # Ignore this packet continue dhcp_reply = d.dhcp_payload(op = d.BOOTREPLY, htype = 1, hlen = 6, hops = 0, xid = dhcp_packet.xid, secs = 0, flags = dhcp_packet.flags, ciaddr = 0, yiaddr = port_ip, siaddr = 0, giaddr = dhcp_packet.giaddr, chaddr = dhcp_packet.chaddr, magic_cookie = d.BOOTP_MAGIC_COOKIE ) set_options(dhcp_reply, option_dict, provide_options, d.DHCPOFFER) elif message_type == d.DHCPREQUEST: if d.OPTION_SERVER_IDENTIFIER in option_dict and option_dict[d.OPTION_SERVER_IDENTIFIER].value != server_ip: # Ignore packets to wrong address continue if dhcp_packet.chaddr[:6].ljust(6, b'\x00') != mac_addr.tobytes(port_mac) \ or (d.OPTION_REQUESTED_IP in option_dict and option_dict[d.OPTION_REQUESTED_IP].value != port_ip) \ or (dhcp_packet.ciaddr != 0 and dhcp_packet.ciaddr != port_ip): dhcp_reply = d.dhcp_payload(op = d.BOOTREPLY, htype = 1, hlen = 6, hops = 0, xid = dhcp_packet.xid, secs = 0, flags = dhcp_packet.flags, ciaddr = 0, yiaddr = 0, siaddr = 0, giaddr = dhcp_packet.giaddr, chaddr = dhcp_packet.chaddr, magic_cookie = d.BOOTP_MAGIC_COOKIE ) d.build_options(dhcp_reply, [d.dhcp_option_message_type(value = d.DHCPNAK), d.dhcp_option_address(tag = d.OPTION_SERVER_IDENTIFIER, value = server_ip)], 576, 0) is_nak = True else: dhcp_reply = d.dhcp_payload(op = d.BOOTREPLY, htype = 1, hlen = 6, hops = 0, xid = dhcp_packet.xid, secs = 0, flags = dhcp_packet.flags, ciaddr = dhcp_packet.ciaddr, yiaddr = port_ip, siaddr = 0, giaddr = dhcp_packet.giaddr, chaddr = dhcp_packet.chaddr, magic_cookie = d.BOOTP_MAGIC_COOKIE ) set_options(dhcp_reply, option_dict, provide_options, d.DHCPACK) elif message_type == d.DHCPDECLINE: self._logger.warning('DHCP client reports DHCPDECLINE, there should be some problems.'\ ' Connection = %r(%016x), port = %d.', self._connection, self._connection.openflow_datapathid) elif message_type == d.DHCPRELEASE: # Safe to ignore continue elif message_type == d.DHCPINFORM: dhcp_reply = d.dhcp_payload(op = d.BOOTREPLY, htype = 1, hlen = 6, hops = 0, xid = dhcp_packet.xid, secs = 0, flags = dhcp_packet.flags, ciaddr = dhcp_packet.ciaddr, yiaddr = 0, siaddr = 0, giaddr = dhcp_packet.giaddr, chaddr = dhcp_packet.chaddr, magic_cookie = d.BOOTP_MAGIC_COOKIE ) set_options(dhcp_reply, option_dict, provide_options, d.DHCPACK, True) trans_id = (trans_id + 1) & 0xffff if (dhcp_packet.flags & d.DHCPFLAG_BROADCAST) or is_nak: dl_dst = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff] ip_dst = 0xffffffff else: dl_dst = l7_packet.dl_src ip_dst = port_ip reply_packet = ip4_packet_l7((ip4_payload, ip4_udp_payload), dl_src = server_mac, dl_dst = dl_dst, identifier = trans_id, ttl = 128, ip_src = server_ip, ip_dst = ip_dst, sport = 67, dport = 68, data = dhcp_reply._tobytes() ) self.subroutine(send_packet(in_port, reply_packet), True) except Exception: self._logger.info('Invalid DHCP packet received: %r', msg.data, exc_info = True)