def handle_dhcp_discover(self, dhcp_pkt, datapath, port): try: # Choose a IP form IP pool list client_ip_addr = str(self.ip_pool_list.pop()) self.mac_to_client_ip[dhcp_pkt.chaddr] = client_ip_addr except IndexError: self.logger.info("EMPTY IP POOL") return # send dhcp_offer message. dhcp_offer_msg_type = '\x02' self.logger.info("Send DHCP message type %s" % (self.dhcp_msg_type_code[ord(dhcp_offer_msg_type)])) msg_option = dhcp.option(tag=dhcp.DHCP_MESSAGE_TYPE_OPT, value=dhcp_offer_msg_type) options = dhcp.options(option_list=[msg_option]) hlen = len(addrconv.mac.text_to_bin(dhcp_pkt.chaddr)) dhcp_pkt = dhcp.dhcp(hlen=hlen, op=dhcp.DHCP_BOOT_REPLY, chaddr=dhcp_pkt.chaddr, yiaddr=client_ip_addr, giaddr=dhcp_pkt.giaddr, xid=dhcp_pkt.xid, options=options) self._send_dhcp_packet(datapath, dhcp_pkt, port)
def create_dhcp_ack(self, dhcp_packet, dp, port, dst_ip="255.255.255.255"): if self.temp_offered.get(dhcp_packet.xid) is None: return subnet_mask = self.space[dp.id].netmask yiaddr = self.temp_offered[dhcp_packet.xid]["yiaddr"] chaddr = self.temp_offered[dhcp_packet.xid]["chaddr"] # add new or update existing dhcp bindings # we remember only last used ip address self.database[chaddr] = yiaddr pkt = packet.Packet() dhcp_ack_msg_type = b"\x05" subnet_option = dhcp.option( tag=dhcp.DHCP_SUBNET_MASK_OPT, value=addrconv.ipv4.text_to_bin(subnet_mask), ) time_option = dhcp.option(tag=dhcp.DHCP_IP_ADDR_LEASE_TIME_OPT, value=bytearray(self.LEASE_TIME_ACK)) msg_option = dhcp.option(tag=dhcp.DHCP_MESSAGE_TYPE_OPT, value=dhcp_ack_msg_type) dhcp_server_option = dhcp.option(tag=dhcp.DHCP_SERVER_IDENTIFIER_OPT, value=bytearray(self._ip_to_int())) options = dhcp.options(option_list=[ msg_option, time_option, subnet_option, dhcp_server_option, ]) hlen = dhcp_packet.hlen dhcp_pkt = dhcp.dhcp( op=dhcp.DHCP_BOOT_REPLY, hlen=hlen, chaddr=dhcp_packet.chaddr, yiaddr=yiaddr, siaddr=self.DHCP_SERVER_IP, giaddr=dhcp_packet.giaddr, xid=dhcp_packet.xid, options=options, ) pkt.add_protocol( ethernet.ethernet(ethertype=ether.ETH_TYPE_IP, dst=chaddr, src=self.DHCP_SERVER_MAC)) pkt.add_protocol( ipv4.ipv4(dst=dst_ip, src=self.DHCP_SERVER_IP, proto=17)) pkt.add_protocol(udp.udp(src_port=67, dst_port=68)) pkt.add_protocol(dhcp_pkt) pkt.serialize() self.inject_packet(pkt, dp, port)
def _send_dhcp_req_to_app(self, lport, 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) return dhcp_response_pkt
def create_dhcp_offer(self, dhcp_packet, dp, port, dst_ip="255.255.255.255"): xid = dhcp_packet.xid # transaction id chaddr = dhcp_packet.chaddr yiaddr = None previous_ip = self.database.get(chaddr) if previous_ip: if previous_ip in self.pools[dp.id]: self.pools[dp.id].remove(previous_ip) yiaddr = previous_ip else: yiaddr = self.pools[dp.id].pop(-1) else: yiaddr = self.pools[dp.id].pop(-1) self.temp_offered[xid] = {"chaddr": chaddr, "yiaddr": yiaddr} pkt = packet.Packet() dhcp_offer_msg_type = b"\x02" hlen = dhcp_packet.hlen msg_option = dhcp.option(tag=dhcp.DHCP_MESSAGE_TYPE_OPT, value=dhcp_offer_msg_type) dhcp_server_option = dhcp.option(tag=dhcp.DHCP_SERVER_IDENTIFIER_OPT, value=bytearray(self._ip_to_int())) options = dhcp.options(option_list=[msg_option, dhcp_server_option]) pkt.add_protocol( ethernet.ethernet(ethertype=ether.ETH_TYPE_IP, dst=chaddr, src=self.DHCP_SERVER_MAC)) pkt.add_protocol( ipv4.ipv4(dst=dst_ip, src=self.DHCP_SERVER_IP, proto=17)) pkt.add_protocol(udp.udp(src_port=67, dst_port=68)) pkt.add_protocol( dhcp.dhcp( hlen=hlen, op=dhcp.DHCP_BOOT_REPLY, yiaddr=yiaddr, siaddr=self.DHCP_SERVER_IP, xid=dhcp_packet.xid, giaddr=dhcp_packet.giaddr, chaddr=chaddr, options=options, )) pkt.serialize() self.inject_packet(pkt, dp, port)
def _create_dhcp_ack(self, pkt, dhcp_packet, lport): pkt_ipv4 = pkt.get_protocol(ipv4.ipv4) pkt_ethernet = pkt.get_protocol(ethernet.ethernet) subnet = self._get_subnet_by_port(lport) if subnet is None: LOG.error(_LE("No subnet found for port <%s>") % lport.get_id()) return dns = self._get_dns_address_list_bin(subnet) host_routes = self._get_host_routes_list_bin(subnet, lport) dhcp_server_address = str(self._get_dhcp_server_address(subnet)) gateway_address = self._get_port_gateway_address(subnet) netmask_bin = self._get_port_netmask(subnet).packed domain_name_bin = struct.pack('!256s', self.domain_name) lease_time_bin = struct.pack('!I', self.lease_time) option_list = [ dhcp.option(dhcp.DHCP_MESSAGE_TYPE_OPT, b'\x05', 1), dhcp.option(dhcp.DHCP_SUBNET_MASK_OPT, netmask_bin, 4), dhcp.option(dhcp.DHCP_GATEWAY_ADDR_OPT, gateway_address.packed, 4), dhcp.option(dhcp.DHCP_IP_ADDR_LEASE_TIME_OPT, lease_time_bin, 4), dhcp.option(dhcp.DHCP_DNS_SERVER_ADDR_OPT, dns, len(dns)), dhcp.option(DHCP_DOMAIN_NAME_OPT, domain_name_bin, len(self.domain_name)), dhcp.option(DHCP_CLASSLESS_ROUTE, host_routes, len(host_routes))] if self.advertise_mtu: intreface_mtu = self._get_port_mtu(lport) mtu_bin = struct.pack('!H', intreface_mtu) option_list.append(dhcp.option( DHCP_INTERFACE_MTU_OPT, mtu_bin, len(mtu_bin))) options = dhcp.options(option_list=option_list) dhcp_ack_pkt = ryu_packet.Packet() dhcp_ack_pkt.add_protocol(ethernet.ethernet( ethertype=ether.ETH_TYPE_IP, dst=pkt_ethernet.src, src=pkt_ethernet.dst)) dhcp_ack_pkt.add_protocol(ipv4.ipv4(dst=pkt_ipv4.src, src=dhcp_server_address, proto=pkt_ipv4.proto)) dhcp_ack_pkt.add_protocol(udp.udp(src_port=67, dst_port=68)) dhcp_ack_pkt.add_protocol(dhcp.dhcp(op=2, chaddr=pkt_ethernet.src, siaddr=dhcp_server_address, boot_file=dhcp_packet.boot_file, yiaddr=lport.get_ip(), xid=dhcp_packet.xid, options=options)) return dhcp_ack_pkt
def _create_dhcp_ack(self, pkt, dhcp_packet, lport): pkt_ipv4 = pkt.get_protocol(ipv4.ipv4) pkt_ethernet = pkt.get_protocol(ethernet.ethernet) subnet = self._get_subnet_by_port(lport) if subnet is None: LOG.error(_LE("No subnet found for port <%s>") % lport.get_id()) return dns = self._get_dns_address_list_bin(subnet) host_routes = self._get_host_routes_list_bin(subnet) dhcp_server_address = str(self._get_dhcp_server_address(subnet)) gateway_address = self._get_port_gateway_address(subnet) netmask_bin = self._get_port_netmask(subnet).packed domain_name_bin = struct.pack('!256s', self.domain_name) lease_time_bin = struct.pack('!I', self.lease_time) option_list = [ dhcp.option(dhcp.DHCP_MESSAGE_TYPE_OPT, b'\x05', 1), dhcp.option(dhcp.DHCP_SUBNET_MASK_OPT, netmask_bin, 4), dhcp.option(dhcp.DHCP_GATEWAY_ADDR_OPT, gateway_address.packed, 4), dhcp.option(dhcp.DHCP_IP_ADDR_LEASE_TIME_OPT, lease_time_bin, 4), dhcp.option(dhcp.DHCP_DNS_SERVER_ADDR_OPT, dns, len(dns)), dhcp.option(DHCP_DOMAIN_NAME_OPT, domain_name_bin, len(self.domain_name)), dhcp.option(DHCP_CLASSLESS_ROUTE, host_routes, len(host_routes))] if self.advertise_mtu: intreface_mtu = self._get_port_mtu(lport) mtu_bin = struct.pack('!H', intreface_mtu) option_list.append(dhcp.option( DHCP_INTERFACE_MTU_OPT, mtu_bin, len(mtu_bin))) options = dhcp.options(option_list=option_list) dhcp_ack_pkt = ryu_packet.Packet() dhcp_ack_pkt.add_protocol(ethernet.ethernet( ethertype=ether.ETH_TYPE_IP, dst=pkt_ethernet.src, src=pkt_ethernet.dst)) dhcp_ack_pkt.add_protocol(ipv4.ipv4(dst=pkt_ipv4.src, src=dhcp_server_address, proto=pkt_ipv4.proto)) dhcp_ack_pkt.add_protocol(udp.udp(src_port=67, dst_port=68)) dhcp_ack_pkt.add_protocol(dhcp.dhcp(op=2, chaddr=pkt_ethernet.src, siaddr=dhcp_server_address, boot_file=dhcp_packet.boot_file, yiaddr=lport.get_ip(), xid=dhcp_packet.xid, options=options)) return dhcp_ack_pkt
def _create_dhcp_offer(self, pkt, dhcp_packet, lport): pkt_ipv4 = pkt.get_protocol(ipv4.ipv4) pkt_ethernet = pkt.get_protocol(ethernet.ethernet) subnet = self._get_subnet_by_port(lport) if subnet is None: LOG.error(_LE("No subnet found for port <%s>") % lport.get_id()) return dns = self._get_dns_address_list_bin(subnet) dhcp_server_address = self._get_dhcp_server_address(subnet) netmask_bin = self._get_port_netmask(subnet).packed lease_time_bin = struct.pack('!I', self.lease_time) gateway_address = self._get_port_gateway_address(subnet) domain_name_bin = struct.pack('!256s', self.domain_name) option_list = [ dhcp.option(dhcp.DHCP_MESSAGE_TYPE_OPT, b'\x02', 1), dhcp.option(dhcp.DHCP_SUBNET_MASK_OPT, netmask_bin, 4), dhcp.option(dhcp.DHCP_DNS_SERVER_ADDR_OPT, dns, len(dns)), dhcp.option(dhcp.DHCP_IP_ADDR_LEASE_TIME_OPT, lease_time_bin, 4), dhcp.option(dhcp.DHCP_SERVER_IDENTIFIER_OPT, dhcp_server_address.packed, 4), dhcp.option(15, domain_name_bin, len(self.domain_name)) ] if gateway_address: option_list.append( dhcp.option(dhcp.DHCP_GATEWAY_ADDR_OPT, gateway_address.packed, 4)) options = dhcp.options(option_list=option_list) dhcp_offer_pkt = ryu_packet.Packet() dhcp_offer_pkt.add_protocol( ethernet.ethernet(ethertype=ether.ETH_TYPE_IP, dst=pkt_ethernet.src, src=pkt_ethernet.dst)) dhcp_offer_pkt.add_protocol( ipv4.ipv4(dst=pkt_ipv4.src, src=str(dhcp_server_address), proto=pkt_ipv4.proto)) dhcp_offer_pkt.add_protocol(udp.udp(src_port=67, dst_port=68)) dhcp_offer_pkt.add_protocol( dhcp.dhcp(op=2, chaddr=pkt_ethernet.src, siaddr=str(dhcp_server_address), boot_file=dhcp_packet.boot_file, yiaddr=lport.get_ip(), xid=dhcp_packet.xid, options=options)) return dhcp_offer_pkt
def _create_dhcp_offer(self, pkt, dhcp_packet, lport): pkt_ipv4 = pkt.get_protocol(ipv4.ipv4) pkt_ethernet = pkt.get_protocol(ethernet.ethernet) subnet = self._get_subnet_by_port(lport) if subnet is None: LOG.error(_LE("No subnet found for port <%s>") % lport.get_id()) return dns = self._get_dns_address_list_bin(subnet) dhcp_server_address = self._get_dhcp_server_address(subnet) netmask_bin = self._get_port_netmask(subnet).packed lease_time_bin = struct.pack('!I', self.lease_time) gateway_address = self._get_port_gateway_address(subnet) domain_name_bin = struct.pack('!256s', self.domain_name) option_list = [ dhcp.option(dhcp.DHCP_MESSAGE_TYPE_OPT, b'\x02', 1), dhcp.option(dhcp.DHCP_SUBNET_MASK_OPT, netmask_bin, 4), dhcp.option(dhcp.DHCP_DNS_SERVER_ADDR_OPT, dns, len(dns)), dhcp.option(dhcp.DHCP_IP_ADDR_LEASE_TIME_OPT, lease_time_bin, 4), dhcp.option(dhcp.DHCP_SERVER_IDENTIFIER_OPT, dhcp_server_address.packed, 4), dhcp.option(15, domain_name_bin, len(self.domain_name))] if gateway_address: option_list.append(dhcp.option( dhcp.DHCP_GATEWAY_ADDR_OPT, gateway_address.packed, 4)) options = dhcp.options(option_list=option_list) dhcp_offer_pkt = ryu_packet.Packet() dhcp_offer_pkt.add_protocol(ethernet.ethernet( ethertype=ether.ETH_TYPE_IP, dst=pkt_ethernet.src, src=pkt_ethernet.dst)) dhcp_offer_pkt.add_protocol(ipv4.ipv4(dst=pkt_ipv4.src, src=str(dhcp_server_address), proto=pkt_ipv4.proto)) dhcp_offer_pkt.add_protocol(udp.udp(src_port=67, dst_port=68)) dhcp_offer_pkt.add_protocol(dhcp.dhcp(op=2, chaddr=pkt_ethernet.src, siaddr=str(dhcp_server_address), boot_file=dhcp_packet.boot_file, yiaddr=lport.get_ip(), xid=dhcp_packet.xid, options=options)) return dhcp_offer_pkt
def _create_dhcp_response(self, packet, dhcp_request, response_type, lport): 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 = subnet.dhcp_ip 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_server_address = subnet.dhcp_ip dhcp_response = ryu_packet.Packet() dhcp_response.add_protocol( ethernet.ethernet(ethertype=ether.ETH_TYPE_IP, dst=pkt_ethernet.src, src=pkt_ethernet.dst)) 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 handle_dhcp_request(self, dhcp_pkt, datapath, port): # send dhcp_ack message. dhcp_ack_msg_type = '\x05' self.logger.info("Send DHCP message type %s" % (self.dhcp_msg_type_code[ord(dhcp_ack_msg_type)])) subnet_option = dhcp.option(tag=dhcp.DHCP_SUBNET_MASK_OPT, value=addrconv.ipv4.text_to_bin( self.ip_network.netmask)) gw_option = dhcp.option(tag=dhcp.DHCP_GATEWAY_ADDR_OPT, value=addrconv.ipv4.text_to_bin(self.gw_addr)) dns_option = dhcp.option(tag=dhcp.DHCP_DNS_SERVER_ADDR_OPT, value=addrconv.ipv4.text_to_bin( self.dns_addr)) time_option = dhcp.option(tag=dhcp.DHCP_IP_ADDR_LEASE_TIME_OPT, value='\xFF\xFF\xFF\xFF') msg_option = dhcp.option(tag=dhcp.DHCP_MESSAGE_TYPE_OPT, value=dhcp_ack_msg_type) id_option = dhcp.option(tag=dhcp.DHCP_SERVER_IDENTIFIER_OPT, value=addrconv.ipv4.text_to_bin( self.dhcp_addr)) options = dhcp.options(option_list=[ msg_option, id_option, time_option, subnet_option, gw_option, dns_option ]) hlen = len(addrconv.mac.text_to_bin(dhcp_pkt.chaddr)) # Look up IP by using client mac address client_ip_addr = self.mac_to_client_ip[dhcp_pkt.chaddr] dhcp_pkt = dhcp.dhcp(op=dhcp.DHCP_BOOT_REPLY, hlen=hlen, chaddr=dhcp_pkt.chaddr, yiaddr=client_ip_addr, giaddr=dhcp_pkt.giaddr, xid=dhcp_pkt.xid, options=options) self._send_dhcp_packet(datapath, dhcp_pkt, port)
def handle_dhcp_request(self, dhcp_pkt, datapath, port): # send dhcp_ack message. dhcp_ack_msg_type = '\x05' self.logger.info("Send DHCP message type %s" % (self.dhcp_msg_type_code[ord(dhcp_ack_msg_type)])) subnet_option = dhcp.option(tag=dhcp.DHCP_SUBNET_MASK_OPT, value=addrconv.ipv4.text_to_bin(self.ip_network.netmask)) gw_option = dhcp.option(tag=dhcp.DHCP_GATEWAY_ADDR_OPT, value=addrconv.ipv4.text_to_bin(self.gw_addr)) dns_option = dhcp.option(tag=dhcp.DHCP_DNS_SERVER_ADDR_OPT, value=addrconv.ipv4.text_to_bin(self.dns_addr)) time_option = dhcp.option(tag=dhcp.DHCP_IP_ADDR_LEASE_TIME_OPT, value='\xFF\xFF\xFF\xFF') msg_option = dhcp.option(tag=dhcp.DHCP_MESSAGE_TYPE_OPT, value=dhcp_ack_msg_type) id_option = dhcp.option(tag=dhcp.DHCP_SERVER_IDENTIFIER_OPT, value=addrconv.ipv4.text_to_bin(self.dhcp_addr)) options = dhcp.options(option_list=[msg_option, id_option, time_option, subnet_option, gw_option, dns_option]) hlen = len(addrconv.mac.text_to_bin(dhcp_pkt.chaddr)) # Look up IP by using client mac address client_ip_addr = self.mac_to_client_ip[dhcp_pkt.chaddr] dhcp_pkt = dhcp.dhcp(op=dhcp.DHCP_BOOT_REPLY, hlen=hlen, chaddr=dhcp_pkt.chaddr, yiaddr=client_ip_addr, giaddr=dhcp_pkt.giaddr, xid=dhcp_pkt.xid, options=options) self._send_dhcp_packet(datapath, dhcp_pkt, port)
def _handle_dhcp(self, pkt_dhcp, datapath, in_port): dhcp_type = ord(pkt_dhcp.options.option_list[0].value) ofproto = datapath.ofproto parser = datapath.ofproto_parser # the message is DHCP_ DISCOVERY if dhcp_type == 1: self.logger.info("Recieve DHCP_DISCOVERY") dhcp_offer = '\x02' self.logger.info("Send DHCP_OFFER") msg_option = dhcp.option(tag=53, value=dhcp_offer) options = dhcp.options(option_list=[msg_option]) # allocate ip to host yiaddr = self.ip_pool[0] # generate the DHCP_OFFER packet pkt_dhcp = dhcp.dhcp(op=2, chaddr=pkt_dhcp.chaddr, options=options, hlen=6, htype=1, xid=pkt_dhcp.xid, ciaddr=pkt_dhcp.ciaddr, yiaddr=yiaddr) pkt = packet.Packet() pkt.add_protocol( ethernet.ethernet(src=self.hw_addr, dst="ff:ff:ff:ff:ff:ff")) pkt.add_protocol( ipv4.ipv4(src=self.ip, dst="255.255.255.255", proto=17)) pkt.add_protocol(udp.udp(src_port=67, dst_port=68)) pkt.add_protocol(pkt_dhcp) self._send_packet(datapath, in_port, pkt) # the message is DHCP_REQUEST if dhcp_type == 3: self.logger.info("Recieve DHCP_REQUEST") dhcp_ack = '\x05' self.logger.info("Send DHCP_ACK") # set packet type msg_option = dhcp.option(tag=53, value=dhcp_ack) # set dhcp valid time time_option = dhcp.option(tag=51, value='\x00\xFF\xFF\xFF') # set net mask mask_option = dhcp.option(tag=1, value=self.netmask) options = dhcp.options( option_list=[msg_option, time_option, mask_option]) yiaddr = self.ip_pool[0] # delete the used ip self.ip_pool.pop(0) # generate the DHCP_ACK pkt_dhcp = dhcp.dhcp(op=5, chaddr=pkt_dhcp.chaddr, options=options, hlen=6, htype=1, xid=pkt_dhcp.xid, ciaddr=pkt_dhcp.ciaddr, yiaddr=yiaddr) pkt = packet.Packet() pkt.add_protocol( ethernet.ethernet(src=self.hw_addr, dst="ff:ff:ff:ff:ff:ff")) pkt.add_protocol( ipv4.ipv4(src=self.ip, dst="255.255.255.255", proto=17)) pkt.add_protocol(udp.udp(src_port=67, dst_port=68)) pkt.add_protocol(pkt_dhcp) self._send_packet(datapath, in_port, pkt) # install flow table 0 cookie = 0 cookie_mask = 0 table_id = 0 next_table_id = 3 priority = 2000 buffer_id = ofproto.OFP_NO_BUFFER print(pkt_dhcp.chaddr) match = parser.OFPMatch(eth_type=0x800, eth_src=pkt_dhcp.chaddr, ip_proto=17, udp_src=68) instruction = [parser.OFPInstructionGotoTable(next_table_id)] req = parser.OFPFlowMod(datapath=datapath, command=ofproto.OFPFC_ADD, cookie=cookie, cookie_mask=cookie_mask, table_id=table_id, priority=priority, match=match, instructions=instruction) datapath.send_msg(req) # insatll flow table 3 table_id = 3 priority = 3000 instruction = [ parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, []) ] req = parser.OFPFlowMod(datapath=datapath, command=ofproto.OFPFC_ADD, cookie=cookie, cookie_mask=cookie_mask, table_id=table_id, priority=priority, out_port=ofproto.OFPP_ANY, match=match, instructions=instruction) datapath.send_msg(req)
class Test_dhcp_offer_with_hlen_zero(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=0, hops=hops, xid=xid, secs=secs, flags=flags, ciaddr=ciaddr, yiaddr=yiaddr, siaddr=siaddr, giaddr=giaddr, sname=sname, boot_file=boot_file) 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 _respond_dhcp(self, datapath, port, pool, pkt_ethernet, pkt_vlan, pkt_ip, pkt_udp, pkt_dhcp): # DHCP message type code options = dict() for option in pkt_dhcp.options.option_list: options[option.tag] = option.value src = pkt_dhcp.chaddr # RESPONSE MSG pkt = packet.Packet() pkt.add_protocol(ethernet.ethernet(ethertype=pkt_ethernet.ethertype, dst=pkt_ethernet.src, src='00:00:00:00:00:00')) if pkt_vlan: pkt.add_protocol(vlan.vlan(cfi=pkt_vlan.cfi, ethertype=pkt_vlan.ethertype, pcp=pkt_vlan.pcp, vid=pkt_vlan.vid)) pkt.add_protocol(ipv4.ipv4(src=pkt_ip.dst, dst=pkt_ip.src, proto=in_proto.IPPROTO_UDP)) pkt.add_protocol(udp.udp(src_port=pkt_udp.dst_port, dst_port=pkt_udp.src_port)) # DISCOVER MSG dhcp_msg_type = ord(options[dhcp.DHCP_MESSAGE_TYPE_OPT]) if dhcp_msg_type == dhcp.DHCP_DISCOVER: msg_type = dhcp.DHCP_OFFER if src in self.leases: offer = self.leases[src] del self.leases[src] self.offers[src] = offer else: offer = self.offers.get(src) if offer is None: if len(pool) == 0: LOG.error("Out of IP addresses") msg_type = dhcp.DHCP_NAK offer = pool[0] if dhcp.DHCP_REQUESTED_IP_ADDR_OPT in options: wanted_ip = IPAddr(addrconv.ipv4.bin_to_text(options[dhcp.DHCP_REQUESTED_IP_ADDR_OPT].value)) if wanted_ip in pool: offer = wanted_ip pool.remove(offer) self.offers[src] = offer wanted_opts = list() if dhcp.DHCP_PARAMETER_REQUEST_LIST_OPT in options: fmt = "s" * len(options[dhcp.DHCP_PARAMETER_REQUEST_LIST_OPT]) wanted_opt_set = struct.unpack(fmt, options[dhcp.DHCP_PARAMETER_REQUEST_LIST_OPT]) for i in wanted_opt_set: wanted_opts.append(ord(i)) option_list = list() option_list.append(dhcp.option(dhcp.DHCP_MESSAGE_TYPE_OPT, chr(msg_type), length=1)) if msg_type is not dhcp.DHCP_NAK: if dhcp.DHCP_SUBNET_MASK_OPT in wanted_opts: option_list.append(dhcp.option(dhcp.DHCP_SUBNET_MASK_OPT, addrconv.ipv4.text_to_bin(self.subnet.toStr()), length=4)) if dhcp.DHCP_GATEWAY_ADDR_OPT in wanted_opts and self.router_addr is not None: option_list.append(dhcp.option(dhcp.DHCP_GATEWAY_ADDR_OPT, addrconv.ipv4.text_to_bin(self.router_addr.toStr()), length=4)) if dhcp.DHCP_DNS_SERVER_ADDR_OPT in wanted_opts and self.dns_addr is not None: option_list.append(dhcp.option(dhcp.DHCP_DNS_SERVER_ADDR_OPT, addrconv.ipv4.text_to_bin(self.dns_addr.toStr()), length=4)) option_list.append(dhcp.option(dhcp.DHCP_IP_ADDR_LEASE_TIME_OPT, chr(self.lease_time), length=4)) option_list.append(dhcp.option(dhcp.DHCP_RENEWAL_TIME_OPT, chr(self.lease_time / 2), length=4)) option_list.append(dhcp.option(dhcp.DHCP_REBINDING_TIME_OPT, chr(self.lease_time * 7 / 8), length=4)) resp_options = dhcp.options(option_list=option_list) pkt.add_protocol(dhcp.dhcp(op=self._MSG_TYPE_BOOT_REPLY, chaddr=pkt_dhcp.chaddr, options=resp_options, xid=pkt_dhcp.xid, ciaddr=pkt_dhcp.ciaddr, yiaddr=offer.toStr(), siaddr=self.ip_addr.toStr(), giaddr='0.0.0.0', sname='', boot_file='')) # REQUEST MSG if dhcp_msg_type == dhcp.DHCP_REQUEST: msg_type = dhcp.DHCP_ACK if dhcp.DHCP_REQUESTED_IP_ADDR_OPT not in options: return wanted_ip = IPAddr(addrconv.ipv4.bin_to_text(options[dhcp.DHCP_REQUESTED_IP_ADDR_OPT])) got_ip = None if src in self.leases: if wanted_ip != self.leases[src]: pool.append(self.leases[src]) del self.leases[src] else: got_ip = self.leases[src] if got_ip is None: if src in self.offers: if wanted_ip != self.offers[src]: pool.append(self.offers[src]) del self.offers[src] else: got_ip = self.offers[src] if got_ip is None: if wanted_ip in pool: pool.remove(wanted_ip) got_ip = wanted_ip if got_ip is None: LOG.warn("%s asked for un-offered %s", src, wanted_ip.toStr()) msg_type = dhcp.DHCP_NAK wanted_opts = list() if dhcp.DHCP_PARAMETER_REQUEST_LIST_OPT in options: fmt = "s" * len(options[dhcp.DHCP_PARAMETER_REQUEST_LIST_OPT]) wanted_opt_set = struct.unpack(fmt, options[dhcp.DHCP_PARAMETER_REQUEST_LIST_OPT]) for i in wanted_opt_set: wanted_opts.append(ord(i)) # DHCP options tag code option_list = list() option_list.append(dhcp.option(dhcp.DHCP_MESSAGE_TYPE_OPT, chr(msg_type), length=1)) if msg_type is not dhcp.DHCP_NAK: if dhcp.DHCP_SUBNET_MASK_OPT in wanted_opts: option_list.append(dhcp.option(dhcp.DHCP_SUBNET_MASK_OPT, addrconv.ipv4.text_to_bin(self.subnet.toStr()), length=4)) if dhcp.DHCP_GATEWAY_ADDR_OPT in wanted_opts and self.router_addr is not None: option_list.append(dhcp.option(dhcp.DHCP_GATEWAY_ADDR_OPT, addrconv.ipv4.text_to_bin(self.router_addr.toStr()), length=4)) if dhcp.DHCP_DNS_SERVER_ADDR_OPT in wanted_opts and self.dns_addr is not None: option_list.append(dhcp.option(dhcp.DHCP_DNS_SERVER_ADDR_OPT, addrconv.ipv4.text_to_bin(self.dns_addr.toStr()), length=4)) option_list.append(dhcp.option(dhcp.DHCP_IP_ADDR_LEASE_TIME_OPT, chr(self.lease_time), length=4)) option_list.append(dhcp.option(dhcp.DHCP_RENEWAL_TIME_OPT, chr(self.lease_time / 2), length=4)) option_list.append(dhcp.option(dhcp.DHCP_REBINDING_TIME_OPT, chr(self.lease_time * 7 / 8), length=4)) resp_options = dhcp.options(option_list=option_list) pkt.add_protocol(dhcp.dhcp(op=self._MSG_TYPE_BOOT_REPLY, chaddr=pkt_dhcp.chaddr, options=resp_options, xid=pkt_dhcp.xid, ciaddr=pkt_dhcp.ciaddr, yiaddr=wanted_ip.toStr(), siaddr=self.ip_addr.toStr(), giaddr='0.0.0.0', sname='', boot_file='')) # RELEASE MSG if dhcp_msg_type == dhcp.DHCP_RELEASE: if self.leases.get(src).toStr() != pkt_dhcp.ciaddr: LOG.warn("%s tried to release unleased %s" % (src, pkt_dhcp.ciaddr)) return del self.leases[src] pool.append(pkt_dhcp.ciaddr) LOG.info("%s released %s" % (src, pkt_dhcp.ciaddr)) self._send_dhcp_reply(datapath, port, pkt) return True
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 = b'' 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 = self.dh.parser(self.buf) if type(_res) is tuple: res = _res[0] else: res = _res 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, b'\x00'), res.boot_file) eq_(str(self.options), str(res.options)) def test_parser_corrupted(self): buf = self.buf[:128 - (14 + 20 + 8)] _res = self.dh.parser(buf) def test_serialize(self): data = bytearray() prev = None buf = self.dh.serialize(data, prev) 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, b'\x00'), res[13]) 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))
def _create_dhcp_packet(self, packet, dhcp_packet, pkt_type, lport): 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 pkt_type_packed = struct.pack('!B', pkt_type) dns = self._get_dns_address_list_bin(subnet) host_routes = self._get_host_routes_list_bin(subnet, lport) dhcp_server_address = subnet.dhcp_ip if not dhcp_server_address: LOG.warning("Could not find DHCP server address for subnet %s", subnet.id) return netmask_bin = subnet.cidr.netmask.packed domain_name_bin = struct.pack('!%ss' % len(self.domain_name), self.domain_name) lease_time_bin = struct.pack('!I', self.lease_time) option_list = [ dhcp.option(dhcp.DHCP_MESSAGE_TYPE_OPT, pkt_type_packed), dhcp.option(dhcp.DHCP_SUBNET_MASK_OPT, netmask_bin), dhcp.option(dhcp.DHCP_IP_ADDR_LEASE_TIME_OPT, lease_time_bin), dhcp.option(dhcp.DHCP_SERVER_IDENTIFIER_OPT, dhcp_server_address.packed), dhcp.option(dhcp.DHCP_DNS_SERVER_ADDR_OPT, dns), dhcp.option(dhcp.DHCP_DOMAIN_NAME_OPT, domain_name_bin), dhcp.option(dhcp.DHCP_CLASSLESS_ROUTE_OPT, host_routes), ] gw_ip = self._get_port_gateway_address(subnet, lport) if gw_ip: option_list.append( dhcp.option(dhcp.DHCP_GATEWAY_ADDR_OPT, netaddr.IPAddress(gw_ip).packed)) if pkt_type == dhcp.DHCP_ACK: intreface_mtu = self._get_port_mtu(lport) mtu_bin = struct.pack('!H', intreface_mtu) option_list.append( dhcp.option(dhcp.DHCP_INTERFACE_MTU_OPT, mtu_bin)) options = dhcp.options(option_list=option_list) dhcp_pkt = ryu_packet.Packet() dhcp_pkt.add_protocol( ethernet.ethernet(ethertype=ether.ETH_TYPE_IP, dst=pkt_ethernet.src, src=pkt_ethernet.dst)) dhcp_pkt.add_protocol( ipv4.ipv4(dst=pkt_ipv4.src, src=dhcp_server_address, proto=pkt_ipv4.proto)) dhcp_pkt.add_protocol( udp.udp(src_port=const.DHCP_SERVER_PORT, dst_port=const.DHCP_CLIENT_PORT)) dhcp_pkt.add_protocol( dhcp.dhcp(op=dhcp.DHCP_BOOT_REPLY, chaddr=pkt_ethernet.src, siaddr=dhcp_server_address, boot_file=dhcp_packet.boot_file, yiaddr=lport.ip, xid=dhcp_packet.xid, options=options)) return dhcp_pkt