def create_vxlan_packet(self, outer_da, outer_sa, outer_dip, outer_sip, vni, inner_da, inner_dip, inner_sa="00:11:22:33:55:66", inner_sip="192.168.0.44", is_inner_vlan=False, vlan_id=1): out_ether = scapy.Ether(dst=outer_da, src=outer_sa) out_ip = scapy.IP(dst=outer_dip, src=outer_sip) out_udp = scapy.UDP(dport=4789, sport=random.randint( 49152, 65535 - NUM_CONTINUOUS_PKT_COUNT)) vxlan = scapy.VXLAN(vni=vni) ether = scapy.Ether(dst=inner_da, src=inner_sa) dot1q = scapy.Dot1Q(vlan=vlan_id) ip = scapy.IP(dst=inner_dip, src=inner_sip) udp = scapy.UDP(dport=22222, sport=11111) # minimum packet for untagged payload = "\0" * (64 - 4 - len(ether / ip / udp)) packet_vxlan = out_ether / out_ip / out_udp / vxlan / ether / ip / udp / payload if is_inner_vlan: packet_inner = ether / dot1q / ip / udp / payload else: packet_inner = ether / ip / udp / payload return packet_vxlan, packet_inner
def generate_expected_packet(self, inner_pkt): """ Generate ip_in_ip packet for verifying. """ inner_pkt = inner_pkt.copy() inner_pkt.ttl = inner_pkt.ttl - 1 pkt = scapy.Ether(dst=self.active_tor_mac, src=self.standby_tor_mac) / \ scapy.IP(src=self.standby_tor_ip, dst=self.active_tor_ip) / inner_pkt['IP'] exp_pkt = Mask(pkt) exp_pkt.set_do_not_care_scapy(scapy.Ether, 'dst') exp_pkt.set_do_not_care_scapy(scapy.IP, "ihl") exp_pkt.set_do_not_care_scapy(scapy.IP, "tos") exp_pkt.set_do_not_care_scapy(scapy.IP, "len") exp_pkt.set_do_not_care_scapy(scapy.IP, "id") exp_pkt.set_do_not_care_scapy(scapy.IP, "flags") exp_pkt.set_do_not_care_scapy(scapy.IP, "frag") exp_pkt.set_do_not_care_scapy(scapy.IP, "ttl") exp_pkt.set_do_not_care_scapy(scapy.IP, "proto") exp_pkt.set_do_not_care_scapy(scapy.IP, "chksum") exp_pkt.set_do_not_care_scapy(scapy.TCP, "sport") exp_pkt.set_do_not_care_scapy(scapy.TCP, "seq") exp_pkt.set_do_not_care_scapy(scapy.TCP, "ack") exp_pkt.set_do_not_care_scapy(scapy.TCP, "reserved") exp_pkt.set_do_not_care_scapy(scapy.TCP, "dataofs") exp_pkt.set_do_not_care_scapy(scapy.TCP, "window") exp_pkt.set_do_not_care_scapy(scapy.TCP, "chksum") exp_pkt.set_do_not_care_scapy(scapy.TCP, "urgptr") exp_pkt.set_ignore_extra_bytes() return exp_pkt
def create_dhcp_discover_relayed_packet(self): my_chaddr = ''.join( [chr(int(octet, 16)) for octet in self.client_mac.split(':')]) # Relay modifies the DHCPDISCOVER message in the following ways: # 1.) Increments the hops count in the DHCP header # 2.) Updates the gateway IP address in hte BOOTP header (if it is 0.0.0.0) # 3.) Replaces the source IP with the IP of the interface which the relay # received the broadcast DHCPDISCOVER message on # 4.) Replaces the destination IP with the IP address of the DHCP server # each message is being forwarded to # Here, the actual destination MAC should be the MAC of the leaf the relay # forwards through and the destination IP should be the IP of the DHCP server # the relay is forwarding to. We don't need to confirm these, so we'll # just mask them off later # # TODO: In IP layer, DHCP relay also replaces source IP with IP of interface on # which it received the broadcast DHCPDISCOVER from client. This appears to # be loopback. We could pull from minigraph and check here. ether = scapy.Ether(dst=self.BROADCAST_MAC, src=self.uplink_mac, type=0x0800) ip = scapy.IP(src=self.DEFAULT_ROUTE_IP, dst=self.BROADCAST_IP, len=328, ttl=64) udp = scapy.UDP(sport=self.DHCP_SERVER_PORT, dport=self.DHCP_SERVER_PORT, len=308) bootp = scapy.BOOTP(op=1, htype=1, hlen=6, hops=1, xid=0, secs=0, flags=0x8000, ciaddr=self.DEFAULT_ROUTE_IP, yiaddr=self.DEFAULT_ROUTE_IP, siaddr=self.DEFAULT_ROUTE_IP, giaddr=self.relay_iface_ip if not self.dual_tor else self.switch_loopback_ip, chaddr=my_chaddr) bootp /= scapy.DHCP( options=[('message-type', 'discover'), ('relay_agent_Information', self.option82), ('end')]) # If our bootp layer is too small, pad it pad_bytes = self.DHCP_PKT_BOOTP_MIN_LEN - len(bootp) if pad_bytes > 0: bootp /= scapy.PADDING('\x00' * pad_bytes) pkt = ether / ip / udp / bootp return pkt
def create_dhcp_ack_relayed_packet(self): my_chaddr = ''.join( [chr(int(octet, 16)) for octet in self.client_mac.split(':')]) # Relay modifies the DHCPACK message in the following ways: # 1.) Replaces the source MAC with the MAC of the interface it received it on # 2.) Replaces the destination MAC with boradcast (ff:ff:ff:ff:ff:ff) # 3.) Replaces the source IP with the IP of the interface which the relay # received it on # 4.) Replaces the destination IP with broadcast (255.255.255.255) # 5.) Replaces the destination port with the DHCP client port (68) ether = scapy.Ether(dst=self.BROADCAST_MAC, src=self.relay_iface_mac, type=0x0800) ip = scapy.IP(src=self.relay_iface_ip, dst=self.BROADCAST_IP, len=290, ttl=64) udp = scapy.UDP(sport=self.DHCP_SERVER_PORT, dport=self.DHCP_CLIENT_PORT, len=262) bootp = scapy.BOOTP(op=2, htype=1, hlen=6, hops=0, xid=0, secs=0, flags=0x8000, ciaddr=self.DEFAULT_ROUTE_IP, yiaddr=self.client_ip, siaddr=self.server_ip, giaddr=self.relay_iface_ip if not self.dual_tor else self.switch_loopback_ip, chaddr=my_chaddr) bootp /= scapy.DHCP(options=[( 'message-type', 'ack'), ('server_id', self.server_ip), ( 'lease_time', self.LEASE_TIME), ('subnet_mask', self.client_subnet), ('end')]) # TODO: Need to add this to the packet creation functions in PTF code first! # If our bootp layer is too small, pad it #pad_bytes = self.DHCP_PKT_BOOTP_MIN_LEN - len(bootp) #if pad_bytes > 0: # bootp /= scapy.PADDING('\x00' * pad_bytes) pkt = ether / ip / udp / bootp return pkt
def simple_nvgrev6_packet(self, pktlen=300, eth_dst='00:01:02:03:04:05', eth_src='00:06:07:08:09:0a', dl_vlan_enable=False, vlan_vid=0, vlan_pcp=0, dl_vlan_cfi=0, ipv6_src='1::2', ipv6_dst='3::4', ipv6_fl=0, ipv6_tc=0, ipv6_ecn=None, ipv6_dscp=None, ipv6_hlim=64, nvgre_version=0, nvgre_tni=None, nvgre_flowid=0, inner_frame=None): ''' @summary: Helper function to construct an IPv6 NVGRE packet ''' if scapy.NVGRE is None: logging.error( "A NVGRE packet was requested but NVGRE is not supported by your Scapy. See README for more information" ) return None if MINSIZE > pktlen: pktlen = MINSIZE nvgre_hdr = scapy.NVGRE(vsid=nvgre_tni, flowid=nvgre_flowid) if (dl_vlan_enable): pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \ scapy.Dot1Q(prio=vlan_pcp, id=dl_vlan_cfi, vlan=vlan_vid)/ \ scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim, nh=47)/ \ nvgre_hdr else: pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \ scapy.IPv6(src=ipv6_src, dst=ipv6_dst, fl=ipv6_fl, tc=ipv6_tc, hlim=ipv6_hlim, nh=47)/ \ nvgre_hdr if inner_frame: pkt = pkt / inner_frame else: pkt = pkt / scapy.IP() pkt = pkt / ("D" * (pktlen - len(pkt))) return pkt
def create_dhcp_discover_relayed_packet(self): my_chaddr = ''.join([ chr(int(octet, 16)) for octet in self.client_iface_mac.split(':') ]) # Relay modifies the DHCPDISCOVER message in the following ways: # 1.) Increments the hops count in the DHCP header # 2.) Updates the gateway IP address in hte BOOTP header (if it is 0.0.0.0) # 3.) Replaces the source IP with the IP of the interface which the relay # received the broadcast DHCPDISCOVER message on # 4.) Replaces the destination IP with the IP address of the DHCP server # each message is being forwarded to # Here, the actual destination MAC should be the MAC of the leaf the relay # forwards through and the destination IP should be the IP of the DHCP server # the relay is forwarding to. We don't need to confirm these, so we'll # just mask them off later # # TODO: Relay also replaces source IP with IP of interface on which it received the # broadcast DHCPDISCOVER from client. This appears to be loopback. # We could pull from minigraph and check here. pkt = scapy.Ether(dst=self.BROADCAST_MAC, src=self.relay_iface_mac, type=0x0800) pkt /= scapy.IP(src=self.DEFAULT_ROUTE_IP, dst=self.BROADCAST_IP, len=328, ttl=64) pkt /= scapy.UDP(sport=self.DHCP_SERVER_PORT, dport=self.DHCP_SERVER_PORT, len=308) pkt /= scapy.BOOTP(op=1, htype=1, hlen=6, hops=1, xid=0, secs=0, flags=0x8000, ciaddr=self.DEFAULT_ROUTE_IP, yiaddr=self.DEFAULT_ROUTE_IP, siaddr=self.DEFAULT_ROUTE_IP, giaddr=self.relay_iface_ip, chaddr=my_chaddr) pkt /= scapy.DHCP(options=[( 'message-type', 'discover'), ('relay_agent_Information', self.relay_agent_info), ('end')]) # The isc-dhcp-relay adds 44 bytes of padding to our discover packet pkt /= scapy.PADDING('\x00' * 44) return pkt
def create_dhcp_request_relayed_packet(self): my_chaddr = ''.join( [chr(int(octet, 16)) for octet in self.client_mac.split(':')]) # Here, the actual destination MAC should be the MAC of the leaf the relay # forwards through and the destination IP should be the IP of the DHCP server # the relay is forwarding to. We don't need to confirm these, so we'll # just mask them off later # # TODO: In IP layer, DHCP relay also replaces source IP with IP of interface on # which it received the broadcast DHCPREQUEST from client. This appears to # be loopback. We could pull from minigraph and check here. ether = scapy.Ether(dst=self.BROADCAST_MAC, src=self.uplink_mac, type=0x0800) ip = scapy.IP(src=self.DEFAULT_ROUTE_IP, dst=self.BROADCAST_IP, len=336, ttl=64) udp = scapy.UDP(sport=self.DHCP_SERVER_PORT, dport=self.DHCP_SERVER_PORT, len=316) bootp = scapy.BOOTP(op=1, htype=1, hlen=6, hops=1, xid=0, secs=0, flags=0x8000, ciaddr=self.DEFAULT_ROUTE_IP, yiaddr=self.DEFAULT_ROUTE_IP, siaddr=self.DEFAULT_ROUTE_IP, giaddr=self.relay_iface_ip if not self.dual_tor else self.switch_loopback_ip, chaddr=my_chaddr) bootp /= scapy.DHCP(options=[( 'message-type', 'request'), ( 'requested_addr', self.client_ip), ( 'server_id', self.server_ip), ('relay_agent_Information', self.option82), ('end')]) # If our bootp layer is too small, pad it pad_bytes = self.DHCP_PKT_BOOTP_MIN_LEN - len(bootp) if pad_bytes > 0: bootp /= scapy.PADDING('\x00' * pad_bytes) pkt = ether / ip / udp / bootp return pkt
def createDhcpRequestRelayedPacket(self, dutMac): """ Helper function that creates DHCP Request packet destined to DUT Args: dutMac(str): MAC address of DUT Returns: packet: DHCP Request packet """ ether = scapy.Ether(dst=dutMac, src=self.DHCP_RELAY["mac"], type=0x0800) ip = scapy.IP(src=self.DHCP_RELAY["loopback"], dst=self.DHCP_SERVER["ip"], len=328, ttl=64) udp = scapy.UDP(sport=self.DHCP_SERVER["port"], dport=self.DHCP_SERVER["port"], len=308) bootp = scapy.BOOTP(op=1, htype=1, hlen=6, hops=1, xid=0, secs=0, flags=0x8000, ciaddr=str(INADDR_ANY), yiaddr=str(INADDR_ANY), siaddr=str(INADDR_ANY), giaddr=self.DHCP_RELAY["ip"], chaddr=''.join([ chr(int(octet, 16)) for octet in self.DHCP_CLIENT["mac"].split(':') ])) bootp /= scapy.DHCP( options=[("message-type", "request"), ("requested_addr", self.DHCP_CLIENT["ip"] ), ("server_id", self.DHCP_SERVER["ip"]), ("end")]) pad_bytes = self.DHCP_PKT_BOOTP_MIN_LEN - len(bootp) if pad_bytes > 0: bootp /= scapy.PADDING("\x00" * pad_bytes) pkt = ether / ip / udp / bootp return pkt
def create_dhcp_request_relayed_packet(self): my_chaddr = ''.join([ chr(int(octet, 16)) for octet in self.client_iface_mac.split(':') ]) # Here, the actual destination MAC should be the MAC of the leaf the relay # forwards through and the destination IP should be the IP of the DHCP server # the relay is forwarding to. We don't need to confirm these, so we'll # just mask them off later # # TODO: Relay also replaces source IP with IP of interface on which it received the # broadcast DHCPDISCOVER from client. This appears to be loopback. # We could pull from minigraph and check here. pkt = scapy.Ether(dst=self.BROADCAST_MAC, src=self.relay_iface_mac, type=0x0800) pkt /= scapy.IP(src=self.DEFAULT_ROUTE_IP, dst=self.BROADCAST_IP, len=328, ttl=64) pkt /= scapy.UDP(sport=self.DHCP_SERVER_PORT, dport=self.DHCP_SERVER_PORT, len=308) pkt /= scapy.BOOTP(op=1, htype=1, hlen=6, hops=1, xid=0, secs=0, flags=0x8000, ciaddr=self.DEFAULT_ROUTE_IP, yiaddr=self.DEFAULT_ROUTE_IP, siaddr=self.DEFAULT_ROUTE_IP, giaddr=self.relay_iface_ip, chaddr=my_chaddr) pkt /= scapy.DHCP(options=[( 'message-type', 'request'), ('requested_addr', self.client_ip), ('server_id', self.server_ip), ('relay_agent_Information', self.relay_agent_info), ('end')]) # The isc-dhcp-relay adds 32 bytes of padding to our request pkt /= scapy.PADDING('\x00' * 32) return pkt
def send_and_verify(self, dst_ip, expected_ports, src_port, triple_encap = False): ''' @summary: This function builds encap packet, send and verify their arrival. @dst_ip: the destination ip for the inner IP header @expected_ports: list of ports that a packet can arrived from @src_port: the physical port that the packet will be sent from @triple_encap: True to send triple encapsulated packet ''' #setting parameters src_mac = self.dataplane.get_mac(0, 0) dst_mac = '00:11:22:33:44:55' inner_src_ip = '2.2.2.2' router_mac = self.test_params['router_mac'] dscp_in = random.randint(0, 32) tos_in = dscp_in << 2 dscp_out = random.randint(0, 32) tos_out = dscp_out << 2 if ("pipe" == self.test_params['dscp_mode']): exp_tos = tos_in elif("uniform" == self.test_params['dscp_mode']): exp_tos = tos_out else: print("ERROR: no dscp is configured") exit() default_packet_len = 100 default_packet_add_header_len = 114 #building the packets and the expected packets if (not triple_encap): #for the double encap packet we will use IP header with TCP header without mac inner_pkt = simple_ip_only_packet(ip_dst=dst_ip, ip_src=inner_src_ip, ip_ttl=64, ip_tos=tos_in) #after the decap process the retuning packet will be normal tcp packet, The TTL is taked from the inner layer and redused by one exp_pkt = simple_tcp_packet(pktlen=default_packet_add_header_len, eth_dst=dst_mac, eth_src=router_mac, ip_dst=dst_ip, ip_src=inner_src_ip, ip_tos=exp_tos, ip_ttl=63) else: #Building triple encap packet with SCAPY, because there is no PTF function for it, I use the defualt values for the TCP header tcp_hdr = scapy.TCP(sport=1234, dport=80, flags="S", chksum=0) inner_pkt2 = scapy.IP(src='4.4.4.4', dst='3.3.3.3', tos=0, ttl=64, id=1, ihl=None) / tcp_hdr inner_pkt = scapy.IP(src=inner_src_ip, dst=dst_ip, tos=tos_in, ttl=64, id=1, ihl=None,proto=4) / inner_pkt2 inner_pkt = inner_pkt/("".join([chr(x) for x in xrange(default_packet_len - len(inner_pkt))])) #The expected packet is also built by scapy, and the TTL is taked from the inner layer and redused by one exp_pkt = scapy.Ether(dst=dst_mac, src=router_mac)/inner_pkt exp_pkt['IP'].tos = exp_tos #this parameter is taken by the decap rule configuration exp_pkt['IP'].ttl = 63 pkt = simple_ipv4ip_packet( eth_dst=router_mac, eth_src=src_mac, ip_src='1.1.1.1', ip_dst=self.test_params['lo_ip'], ip_tos=tos_out, ip_ttl=random.randint(2, 63), inner_frame=inner_pkt) #send and verify the return packets masked_exp_pkt = Mask(exp_pkt) masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst") masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "src") send_packet(self, src_port, pkt) logging.info(".....Sending packet from port" + str(src_port) + " to " + dst_ip + ", Triple_encap: " + str(triple_encap)) (matched, received) = verify_packet_any_port(self, masked_exp_pkt, expected_ports) assert received return (matched, received)