def test_encap(self): """Packet Tracer Filter Test with encap""" # the packet we are trying to match p = ( Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / UDP() / VXLAN() / Ether() / IP() / UDP() / GENEVE(vni=1234) / Ether() / IP(src="192.168.4.167") / UDP() / Raw("\xa5" * 100) ) # # compute filter mask & value # we compute it by XOR'ing a template packet with a modified packet # we need to set checksums to 0 to make sure scapy will not recompute # them # tmpl = ( Ether() / IP(chksum=0) / UDP(chksum=0) / VXLAN() / Ether() / IP(chksum=0) / UDP(chksum=0) / GENEVE(vni=0) / Ether() / IP(src="0.0.0.0", chksum=0) ) ori = raw(tmpl) # the mask tmpl[GENEVE].vni = 0xFFFFFF user = tmpl[GENEVE].payload user[IP].src = "255.255.255.255" new = raw(tmpl) mask = "".join(("{:02x}".format(o ^ n) for o, n in zip(ori, new))) # this does not match (wrong vni) tmpl[GENEVE].vni = 1 user = tmpl[GENEVE].payload user[IP].src = "192.168.4.167" new = raw(tmpl) match = "".join(("{:02x}".format(o ^ n) for o, n in zip(ori, new))) self.assert_classify(mask, match, [p] * 11, 0) # this must match tmpl[GENEVE].vni = 1234 new = raw(tmpl) match = "".join(("{:02x}".format(o ^ n) for o, n in zip(ori, new))) self.assert_classify(mask, match, [p] * 17)
def encap_mcast(self, pkt, src_ip, src_mac, vni): """ Encapsulate the original payload frame by adding GENEVE header with its UDP, IP and Ethernet fields """ return (Ether(src=src_mac, dst=self.mcast_mac) / IP(src=src_ip, dst=self.mcast_ip4) / UDP(sport=self.dport, dport=self.dport, chksum=0) / GENEVE(vni=vni) / pkt)
def encapsulate(self, pkt, vni): """ Encapsulate the original payload frame by adding GENEVE header with its UDP, IP and Ethernet fields """ return (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / UDP(sport=self.dport, dport=self.dport, chksum=0) / GENEVE(vni=vni) / pkt)
def test_l3_packet(self): vni = 1234 r = self.vapi.add_node_next(node_name="geneve4-input", next_name="ethernet-input") r = self.vapi.geneve_add_del_tunnel2( is_add=1, local_address=self.pg0.local_ip4, remote_address=self.pg0.remote_ip4, vni=vni, l3_mode=1, decap_next_index=r.next_index, ) self.vapi.sw_interface_add_del_address(sw_if_index=r.sw_if_index, prefix="10.0.0.1/24") pkt = (Ether(src=self.pg0.remote_mac, dst="d0:0b:ee:d0:00:00") / IP(src="10.0.0.2", dst="10.0.0.1") / ICMP()) encap = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / UDP(sport=6081, dport=6081, chksum=0) / GENEVE(vni=vni)) arp = Ether(src=self.pg0.remote_mac, dst="d0:0b:ee:d0:00:00") / ARP( op="is-at", hwsrc=self.pg0.remote_mac, hwdst="d0:0b:ee:d0:00:00", psrc="10.0.0.2", pdst="10.0.0.1", ) rx = self.send_and_expect(self.pg0, encap / pkt * 1, self.pg0) rx = self.send_and_assert_no_replies(self.pg0, encap / arp * 1, self.pg0) rx = self.send_and_expect(self.pg0, encap / pkt * 1, self.pg0) self.assertEqual(rx[0][ICMP].type, 0) # echo reply r = self.vapi.geneve_add_del_tunnel2( is_add=0, local_address=self.pg0.local_ip4, remote_address=self.pg0.remote_ip4, vni=vni, )
def define_packets(self): """Defines the packets to be sent from the traffic generator. Packet definition: | ETH | IP | UDP | :returns: Packets to be sent from the traffic generator. :rtype: tuple """ p1_src_start_ip_int = int(IPv4Address(self.p1_src_start_ip)) p1_dst_start_ip_int = int(IPv4Address(self.p1_dst_start_ip)) p2_inner_src_start_ip_int = int(IPv4Address( self.p2_inner_src_start_ip)) p2_inner_dst_start_ip_int = int(IPv4Address( self.p2_inner_dst_start_ip)) # Direction 0 --> 1 base_pkt_a = ( Ether() / IP(src=self.p1_src_start_ip, dst=self.p1_dst_start_ip, proto=61)) # Direction 1 --> 0 base_pkt_b = ( Ether() / IP(src=self.p2_outer_src_ip, dst=self.p2_outer_dst_ip, proto=17) / UDP(sport=self.p2_udp_sport_start, dport=self.p2_udp_dport) / GENEVE(vni=self.p2_geneve_start_vni) / Ether(dst=self.p2_inner_dst_mac) / IP(src=self.p2_inner_src_start_ip, dst=self.p2_inner_dst_start_ip, proto=61)) base_pkt_b /= Raw(load=self._gen_payload(110 - len(base_pkt_b))) # Direction 0 --> 1 vm1 = STLScVmRaw([ STLVmFlowVar(name=u"ip_src", min_value=p1_src_start_ip_int, max_value=p1_src_start_ip_int + self.n_tunnels * 256 - 1, size=4, op=u"inc"), STLVmWrFlowVar(fv_name=u"ip_src", pkt_offset=u"IP.src"), STLVmFlowVar(name=u"ip_dst", min_value=p1_dst_start_ip_int, max_value=p1_dst_start_ip_int + self.n_tunnels * 256 - 1, size=4, op=u"inc"), STLVmWrFlowVar(fv_name=u"ip_dst", pkt_offset=u"IP.dst"), STLVmFixIpv4(offset=u"IP") ]) # Direction 1 --> 0 vm2 = STLScVmRaw([ STLVmFlowVar(name=u"ip", min_value=0, max_value=self.n_tunnels * 256 - 1, size=4, op=u"inc"), STLVmWrMaskFlowVar(fv_name=u"ip", pkt_cast_size=4, mask=0xffffffff, add_value=p2_inner_src_start_ip_int, pkt_offset=u"IP:1.src"), STLVmWrMaskFlowVar(fv_name=u"ip", pkt_cast_size=4, mask=0xffffffff, add_value=p2_inner_dst_start_ip_int, pkt_offset=u"IP:1.dst"), STLVmWrMaskFlowVar(fv_name=u"ip", pkt_cast_size=2, mask=0xffff, add_value=self.p2_udp_sport_start, pkt_offset=u"UDP.sport"), STLVmWrMaskFlowVar(fv_name=u"ip", pkt_cast_size=4, mask=0xffffff00, add_value=(self.p2_geneve_start_vni << 8), pkt_offset=u"GENEVE.vni"), STLVmWrMaskFlowVar( fv_name=u"ip", pkt_cast_size=4, mask=0xffffff, shift=-8, offset_fixup=2, add_value=c_int( int(self.p2_inner_dst_mac.replace(u":", u"")[6:12], 16) << 8).value, pkt_offset=u"Ether:1.dst"), STLVmFixIpv4(offset=u"IP:1"), STLVmFixIpv4(offset=u"IP"), STLVmFixChecksumHw(l3_offset=u"IP", l4_offset=u"UDP", l4_type=CTRexVmInsFixHwCs.L4_TYPE_UDP) ]) return base_pkt_a, base_pkt_b, vm1, vm2
def main(): """Send and receive GENEVE packets.""" args = TrafficScriptArg( [ u"tx_src_mac", u"tx_dst_mac", u"rx_src_mac", u"rx_dst_mac", u"tun_local_ip", u"tun_remote_ip", u"tun_vni", u"tun_src_ip", u"tun_dst_ip" ] ) tx_txq = TxQueue(args.get_arg(u"tx_if")) tx_rxq = RxQueue(args.get_arg(u"tx_if")) rx_txq = TxQueue(args.get_arg(u"rx_if")) rx_rxq = RxQueue(args.get_arg(u"rx_if")) rx_src_mac = args.get_arg(u"rx_src_mac") rx_dst_mac = args.get_arg(u"rx_dst_mac") tx_src_mac = args.get_arg(u"tx_src_mac") tx_dst_mac = args.get_arg(u"tx_dst_mac") tun_local_ip = args.get_arg(u"tun_local_ip") tun_remote_ip = args.get_arg(u"tun_remote_ip") tun_vni = args.get_arg(u"tun_vni") tun_src_ip = args.get_arg(u"tun_src_ip") tun_dst_ip = args.get_arg(u"tun_dst_ip") geneve_tunnel_mac = u"d0:0b:ee:d0:00:00" geneve_udp_dport = 6081 tx_sent_packets = list() src_ip = ip_address(tun_src_ip) dst_ip = ip_address(tun_dst_ip) ip_layer = IP if src_ip.version == 4 else IPv6 tx_ip_pkt = ip_layer(src=src_ip, dst=dst_ip, proto=61) \ if ip_layer == IP else ip_layer(src=src_ip, dst=dst_ip) tx_pkt_send = (Ether(src=tx_src_mac, dst=tx_dst_mac) / tx_ip_pkt) tx_pkt_send /= Raw() size_limit = 78 if ip_layer == IPv6 else 60 if len(tx_pkt_send) < size_limit: tx_pkt_send[Raw].load += b"\0" * (size_limit - len(tx_pkt_send)) tx_sent_packets.append(tx_pkt_send) tx_txq.send(tx_pkt_send) while True: rx_pkt_recv = rx_rxq.recv(2) if rx_pkt_recv is None: raise RuntimeError(f"GENEVE packet Rx timeout") if rx_pkt_recv.haslayer(ICMPv6ND_NS): # read another packet in the queue if the current one is ICMPv6ND_NS continue else: # otherwise process the current packet break check_geneve( rx_pkt_recv, ip_layer, rx_src_mac, rx_dst_mac, geneve_tunnel_mac, rx_dst_mac, tun_local_ip, tun_remote_ip, str(src_ip), str(dst_ip), geneve_udp_dport, int(tun_vni) ) rx_inner_ip_pkt = IP( src=rx_pkt_recv[Ether:2][IP].dst, dst=rx_pkt_recv[Ether:2][IP].src, proto=61 ) if isinstance(rx_pkt_recv[Ether:2][1], IP) else IPv6( src=rx_pkt_recv[Ether:2][IPv6].dst, dst=rx_pkt_recv[Ether:2][IPv6].src ) rx_inner_ip_pkt /= Raw() rx_inner_pkt = ( Ether(src=rx_pkt_recv[4].dst, dst=rx_pkt_recv[4].src) / rx_inner_ip_pkt ) size_limit = 78 if isinstance(rx_pkt_recv[Ether:2][1], IPv6) else 60 if len(rx_inner_pkt) < size_limit: rx_inner_pkt[Raw].load += b"\0" * (size_limit - len(rx_inner_pkt)) rx_outer_ip_pkt = IP( src=rx_pkt_recv[Ether:1][IP].dst, dst=rx_pkt_recv[Ether:1][IP].src ) if isinstance(rx_pkt_recv[Ether:1][1], IP) else IPv6( src=rx_pkt_recv[Ether:1][IPv6].dst, dst=rx_pkt_recv[Ether:1][IPv6].src ) rx_pkt_send = ( Ether(src=rx_pkt_recv[Ether:1].dst, dst=rx_pkt_recv[Ether:1].src) / rx_outer_ip_pkt / UDP(sport=6081, dport=6081) / GENEVE(vni=rx_pkt_recv[GENEVE].vni) / rx_inner_pkt ) rx_txq.send(rx_pkt_send) while True: tx_pkt_recv = tx_rxq.recv(2, ignore=tx_sent_packets) ip_layer = IP if tx_pkt_recv is None: raise RuntimeError(f"{ip_layer.__name__} packet Rx timeout") if tx_pkt_recv.haslayer(ICMPv6ND_NS): # read another packet in the queue if the current one is ICMPv6ND_NS continue else: # otherwise process the current packet break check_ip( tx_pkt_recv, ip_layer, tx_dst_mac, tx_src_mac, str(dst_ip), str(src_ip) ) sys.exit(0)
def craft_pkt(_types, _dicts): pkt = None for i in range(len(_types)): _type = _types[i] _dict = _dicts[i] logging.debug("type: {}, dict: {}".format(_type, _dict)) if _type == "Ether": if 'smac' not in _dict.keys() or \ 'dmac' not in _dict.keys(): raise Exception('Ether: smac and/or dmac not found') else: if pkt: pkt = pkt / Ether(src=_dict['smac'], dst=_dict['dmac']) else: pkt = Ether(src=_dict['smac'], dst=_dict['dmac']) elif _type == "Dot1Q": if 'vlan' not in _dict.keys(): raise Exception('Dot1Q: vlan not found') else: pkt = pkt / Dot1Q(vlan=int(_dict['vlan'])) elif _type == "IP": if 'sip' not in _dict.keys() or \ 'dip' not in _dict.keys(): raise Exception('IP: sip and/or dip not found') else: pkt = pkt / IP(src=_dict['sip'], dst=_dict['dip'], id=0) if 'flags' in _dict.keys(): pkt.getlayer('IP').flags = _dict['flags'] if 'ttl' in _dict.keys(): pkt.getlayer('IP').ttl = _dict['ttl'] elif _type == "UDP": if 'sport' not in _dict.keys() or \ 'dport' not in _dict.keys(): raise Exception('UDP: sport and/or dport not found') else: pkt = pkt / UDP(sport=int(_dict['sport']), dport=int(_dict['dport'])) elif _type == "TCP": if 'sport' not in _dict.keys() or \ 'dport' not in _dict.keys(): raise Exception('TCP: sport and/or dport not found') elif 'flags' in _dict.keys(): pkt = pkt / TCP(sport=int(_dict['sport']), dport=int(_dict['dport']), flags=_dict['flags']) else: pkt = pkt / TCP(sport=int(_dict['sport']), dport=int(_dict['dport'])) elif _type == "ICMP": if 'icmp_type' not in _dict.keys() or \ 'icmp_code' not in _dict.keys(): raise Exception('ICMP: icmp_type and/or icmp_code not found') else: pkt = pkt / ICMP(type=int(_dict['icmp_type']), code=int(_dict['icmp_code'])) elif _type == "MPLS": if 'label' not in _dict.keys() or \ 's' not in _dict.keys(): raise Exception('MPLS: label and/or s not found') else: pkt = pkt / MPLS(label=int(_dict['label']), s=int(_dict['s'])) elif _type == "GENEVE": if 'vni' not in _dict.keys() or \ 'options' not in _dict.keys(): raise Exception('GENEVE: vni and/or options not found') else: pkt = pkt / GENEVE(vni=int(_dict['vni']), options=_dict['options']) return pkt
TCP(sport=0x03e8, dport=0x2710, flags='S') / payload dump_pkt(ipv4_tcp) print('H2S L2 TCP EXP S') payload = 'abcdefghijlkmnopqrstuvwzxyabcdefghijlkmnopqrstuvwzxy' opt_src_slot_id='\x00\x00\x21\x01\x00\x10\x20\x30' opt_dst_slot_id='\x00\x00\x22\x01\x00\x01\x23\x52' geneve_options=opt_src_slot_id + opt_dst_slot_id geneve_ipv4_tcp_exp = Ether(dst='00:06:07:08:09:0A', src='00:01:02:03:04:05') / \ Dot1Q(vlan=2) / \ IP(dst='1.2.3.4', src='4.3.2.1', id=0, ttl=64) / \ UDP(sport=0x0, chksum=0) / \ GENEVE(vni=0xA0B0C0, options=geneve_options) / \ Ether(dst='00:00:F1:D0:D1:D0', src='00:00:00:40:08:01') / \ IP(dst='192.0.2.1', src='2.0.0.1', id=0, ttl=64) / \ TCP(sport=0x03e8, dport=0x2710, flags='S') / payload dump_pkt(geneve_ipv4_tcp_exp) print('S2H L2 TCP INJ SA') payload = 'abcdefghijlkmnopqrstuvwzxyabcdefghijlkmnopqrstuvwzxy' opt_src_slot_id='\x00\x00\x21\x01\x00\x10\x20\x30' opt_dst_slot_id='\x00\x00\x22\x01\x00\x01\x23\x52' geneve_options=opt_src_slot_id + opt_dst_slot_id geneve_ipv4_tcp_inj = Ether(dst='00:01:02:03:04:05', src='00:06:07:08:09:0A') / \