def __init__(self): ## Ethernet frame which is send to pg0 interface and is forwarded to pg1 self.payload_0_1 = ( Ether(src='00:00:00:00:00:01', dst='00:00:00:00:00:02') / IP(src='1.2.3.4', dst='4.3.2.1') / UDP(sport=10000, dport=20000) / Raw('\xa5' * 100)) ## Ethernet frame which is send to pg1 interface and is forwarded to pg0 self.payload_1_0 = ( Ether(src='00:00:00:00:00:02', dst='00:00:00:00:00:01') / IP(src='4.3.2.1', dst='1.2.3.4') / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100))
def verify_keepalive(self, p): pkt = (Ether(src=self.tun_if.remote_mac, dst=self.tun_if.local_mac) / IP(src=p.remote_tun_if_host, dst=self.tun_if.local_ip4) / UDP(sport=333, dport=4500) / Raw(0xff)) self.send_and_assert_no_replies(self.tun_if, pkt * 31) self.assert_error_counter_equal( '/err/%s/NAT Keepalive' % self.tun4_input_node, 31) pkt = (Ether(src=self.tun_if.remote_mac, dst=self.tun_if.local_mac) / IP(src=p.remote_tun_if_host, dst=self.tun_if.local_ip4) / UDP(sport=333, dport=4500) / Raw(0xfe)) self.send_and_assert_no_replies(self.tun_if, pkt * 31) self.assert_error_counter_equal( '/err/%s/Too Short' % self.tun4_input_node, 31)
def create_stream(self, pg_id): # TODO: use variables to create lists based on interface number pg_targets = [None] * 4 pg_targets[0] = [1] pg_targets[1] = [0] pg_targets[2] = [3] pg_targets[3] = [2] pkts = [] for i in range(0, TestL2xc.pkts_per_burst): target_pg_id = pg_targets[pg_id][0] target_host_id = random.randrange(len(self.MY_MACS[target_pg_id])) source_host_id = random.randrange(len(self.MY_MACS[pg_id])) pkt_info = self.create_packet_info(pg_id, target_pg_id) payload = self.info_to_payload(pkt_info) p = (Ether(dst=self.MY_MACS[target_pg_id][target_host_id], src=self.MY_MACS[pg_id][source_host_id]) / IP(src=self.MY_IP4S[pg_id][source_host_id], dst=self.MY_IP4S[target_pg_id][target_host_id]) / UDP(sport=1234, dport=1234) / Raw(payload)) pkt_info.data = p.copy() packet_sizes = [64, 512, 1518, 9018] size = packet_sizes[(i / 2) % len(packet_sizes)] self.extend_packet(p, size) pkts.append(p) return pkts
def test_encap_big_packet(self): """ Encapsulation test send big frame from pg1 Verify receipt of encapsulated frames on pg0 """ self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1500, 0, 0, 0]) frame = (Ether(src='00:00:00:00:00:02', dst='00:00:00:00:00:01') / IP(src='4.3.2.1', dst='1.2.3.4') / UDP(sport=20000, dport=10000) / Raw('\xa5' * 1450)) self.pg1.add_stream([frame]) self.pg0.enable_capture() self.pg_start() # Pick first received frame and check if it's correctly encapsulated. out = self.pg0.get_capture(2) ether = out[0] pkt = reassemble4(out) pkt = ether / pkt self.check_encapsulation(pkt, self.single_tunnel_bd) payload = self.decapsulate(pkt)
def gen_encrypt_pkts(self, sa, sw_intf, src, dst, count=1, payload_size=54): return [ Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) / sa.encrypt( IP(src=src, dst=dst) / ICMP() / Raw('X' * payload_size)) for i in range(count) ]
def gen_encrypt_pkts(self, sa, sw_intf, src, dst, count=1, payload_size=100): return [ Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) / sa.encrypt( IP(src=sw_intf.remote_ip4, dst=sw_intf.local_ip4) / IP(src=src, dst=dst) / UDP(sport=1144, dport=2233) / Raw('X' * payload_size)) for i in range(count) ]
def gen_encrypt_pkts(self, sa, sw_intf, src, dst, count=1, payload_size=100): return [ Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) / sa.encrypt( IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / GRE() / Ether(dst=self.omac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1144, dport=2233) / Raw(b'X' * payload_size)) for i in range(count) ]
def send_encrypted_request(self): """ Make an AEAD GET Request to example.org :return: """ self.logger.info("Making GET Request") # Generate forward secure keys if it hasn't already been done. current_app_key = SessionInstance.get_instance().app_keys if current_app_key['type'] != "FORWARD" or current_app_key[ 'mah'] != SessionInstance.get_instance().last_received_shlo: if len(SessionInstance.get_instance().peer_public_value) == 0: pass else: key = dhke.generate_keys( SessionInstance.get_instance().peer_public_value, True, self.logger) SessionInstance.get_instance().app_keys['type'] = "FORWARD" SessionInstance.get_instance().app_keys[ 'mah'] = SessionInstance.get_instance().last_received_shlo SessionInstance.get_instance().app_keys['key'] = key get_request = "800300002501250000000500000000FF418FF1E3C2E5F23A6BA0AB9EC9AE38110782848750839BD9AB7A85ED6988B4C7" packet_number = PacketNumberInstance.get_instance( ).get_next_packet_number() ciphertext = CryptoManager.encrypt(bytes.fromhex(get_request), packet_number, SessionInstance.get_instance(), self.logger) # Send it to the server a = AEADRequestPacket() a.setfieldval( 'CID', string_to_ascii(SessionInstance.get_instance().connection_id)) a.setfieldval("Public Flags", 0x18) a.setfieldval('Packet Number', packet_number) a.setfieldval("Message Authentication Hash", string_to_ascii(ciphertext[0:24])) p = IP(dst=SessionInstance.get_instance().destination_ip) / UDP( dport=6121, sport=61250) / a / Raw(load=string_to_ascii(ciphertext[24:])) self.sniffer.add_observer(self) send(p) self.wait_for_signal_or_expiration() self.processed = False self.sniffer.remove_observer(self)
def send_frames(payload_len, dump_size, dump_filename): """ Send frames function send the frames. """ for int_iterator in range(dump_size): l2_header = Ether(src="00:11:22:33:44:55", dst="55:44:33:22:11") l3_header = IP(src="192.168.1.1", dst="192.168.1.2", id=int_iterator) payload = Raw( make_payload(PAYLOAD_SEED, payload_len.rand_payload_len(), len(l3_header))) pkt = l2_header / l3_header / payload sendp(pkt, iface=dump_filename, verbose=False) if int_iterator % 100 == 0: print "... " + str(int_iterator) + " packets sent..."
def close_connection(self): """ We do this the unfriendly way, since GoAway does not work. friendly way by means of a Go Away :return: """ frame_data = "02" # frame type frame_data += "00000000" # error code, no error # frame_data += "00000000" # latest responded stream Id frame_data += "0000" # No reason therefore length of 0 # encrypt it packet_number = PacketNumberInstance.get_instance( ).get_next_packet_number() ciphertext = CryptoManager.encrypt(bytes.fromhex(frame_data), packet_number, SessionInstance.get_instance(), self.logger) a = AEADRequestPacket() a.setfieldval("Public Flags", 0x18) a.setfieldval('Packet Number', packet_number) a.setfieldval("Message Authentication Hash", string_to_ascii(ciphertext[0:24])) a.setfieldval( 'CID', string_to_ascii(SessionInstance.get_instance().connection_id)) self.logger.info("Closing connection {}".format( SessionInstance.get_instance().connection_id)) self.logger.info("With ciphertext {}".format(ciphertext)) p = IP(dst=SessionInstance.get_instance().destination_ip) / UDP( dport=6121, sport=61250) / a / Raw(load=string_to_ascii(ciphertext[24:])) # ans, _ = sr(p, count=3) send(p) self.wait_for_signal_or_expiration() self.processed = False self.sniffer.remove_observer(self) time.sleep(1)
def send_ping(self): print("Sending ping message...") ping = PingPacket() ping.setfieldval( 'CID', string_to_ascii(SessionInstance.get_instance().connection_id)) packet_number = PacketNumberInstance.get_instance( ).get_next_packet_number() ciphertext = CryptoManager.encrypt(bytes.fromhex("07"), packet_number, SessionInstance.get_instance()) ping.setfieldval('Packet Number', packet_number) ping.setfieldval("Message Authentication Hash", string_to_ascii(ciphertext[:24])) conf.L3socket = L3RawSocket p = IP(dst=SessionInstance.get_instance().destination_ip) / UDP( dport=6121, sport=61250) / ping / Raw(load=string_to_ascii(ciphertext[24:])) # Maybe we cannot assume that is just a version negotiation packet? send(p)
def frame_reply(self): """ Ethernet frame modeling a generic reply """ return (Ether(src='00:00:00:00:00:02', dst='00:00:00:00:00:01') / IP(src='4.3.2.1', dst='1.2.3.4') / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100))
def test_map_t(self): """ MAP-T """ # # Add a domain that maps from pg0 to pg1 # map_dst = '2001:db8::/32' map_src = '1234:5678:90ab:cdef::/64' ip4_pfx = '192.168.0.0/24' tag = 'MAP-T Tag.' self.vapi.map_add_domain(ip6_prefix=map_dst, ip4_prefix=ip4_pfx, ip6_src=map_src, ea_bits_len=16, psid_offset=6, psid_length=4, mtu=1500, tag=tag) # Enable MAP-T on interfaces. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=1) self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=1) # Ensure MAP doesn't steal all packets! v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) / UDP(sport=20000, dport=10000) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg0, v4 * 1, self.pg0) v4_reply = v4[1] v4_reply.ttl -= 1 for p in rx: self.validate(p[1], v4_reply) # Ensure MAP doesn't steal all packets v6 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6) / UDP(sport=20000, dport=10000) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg1, v6 * 1, self.pg1) v6_reply = v6[1] v6_reply.hlim -= 1 for p in rx: self.validate(p[1], v6_reply) map_route = VppIpRoute(self, "2001:db8::", 32, [ VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ]) map_route.add_vpp_config() # # Send a v4 packet that will be translated # p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1') payload = TCP(sport=0xabcd, dport=0xabcd) p4 = (p_ether / p_ip4 / payload) p6_translated = (IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f") / payload) p6_translated.hlim -= 1 rx = self.send_and_expect(self.pg0, p4 * 1, self.pg1) for p in rx: self.validate(p[1], p6_translated) # Send back an IPv6 packet that will be "untranslated" p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) p_ip6 = IPv6(src='2001:db8:1f0::c0a8:1:f', dst='1234:5678:90ab:cdef:ac:1001:200:0') p6 = (p_ether6 / p_ip6 / payload) p4_translated = (IP(src='192.168.0.1', dst=self.pg0.remote_ip4) / payload) p4_translated.id = 0 p4_translated.ttl -= 1 rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0) for p in rx: self.validate(p[1], p4_translated) # IPv4 TTL ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=0) p4 = (p_ether / ip4_ttl_expired / payload) icmp4_reply = ( IP(id=0, ttl=254, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) / ICMP(type='time-exceeded', code='ttl-zero-during-transit') / IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=0) / payload) rx = self.send_and_expect(self.pg0, p4 * 1, self.pg0) for p in rx: self.validate(p[1], icmp4_reply) ''' This one is broken, cause it would require hairpinning... # IPv4 TTL TTL1 ip4_ttl_expired = IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=1) p4 = (p_ether / ip4_ttl_expired / payload) icmp4_reply = IP(id=0, ttl=254, src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) / \ ICMP(type='time-exceeded', code='ttl-zero-during-transit' ) / \ IP(src=self.pg0.remote_ip4, dst='192.168.0.1', ttl=0) / payload rx = self.send_and_expect(self.pg0, p4*1, self.pg0) for p in rx: self.validate(p[1], icmp4_reply) ''' # IPv6 Hop limit ip6_hlim_expired = IPv6(hlim=0, src='2001:db8:1ab::c0a8:1:ab', dst='1234:5678:90ab:cdef:ac:1001:200:0') p6 = (p_ether6 / ip6_hlim_expired / payload) icmp6_reply = (IPv6( hlim=255, src=self.pg1.local_ip6, dst="2001:db8:1ab::c0a8:1:ab") / ICMPv6TimeExceeded(code=0) / IPv6(src="2001:db8:1ab::c0a8:1:ab", dst='1234:5678:90ab:cdef:ac:1001:200:0', hlim=0) / payload) rx = self.send_and_expect(self.pg1, p6 * 1, self.pg1) for p in rx: self.validate(p[1], icmp6_reply) # IPv4 Well-known port p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1') payload = UDP(sport=200, dport=200) p4 = (p_ether / p_ip4 / payload) self.send_and_assert_no_replies(self.pg0, p4 * 1) # IPv6 Well-known port payload = UDP(sport=200, dport=200) p6 = (p_ether6 / p_ip6 / payload) self.send_and_assert_no_replies(self.pg1, p6 * 1) # Packet fragmentation payload = UDP(sport=40000, dport=4000) / self.payload(1453) p4 = (p_ether / p_ip4 / payload) self.pg_enable_capture() self.pg0.add_stream(p4) self.pg_start() rx = self.pg1.get_capture(2) for p in rx: pass # TODO: Manual validation # self.validate(p[1], icmp4_reply) # Packet fragmentation send fragments payload = UDP(sport=40000, dport=4000) / self.payload(1453) p4 = (p_ether / p_ip4 / payload) frags = fragment(p4, fragsize=1000) self.pg_enable_capture() self.pg0.add_stream(frags) self.pg_start() rx = self.pg1.get_capture(2) for p in rx: pass # p.show2() # reass_pkt = reassemble(rx) # p4_reply.ttl -= 1 # p4_reply.id = 256 # self.validate(reass_pkt, p4_reply) # TCP MSS clamping self.vapi.map_param_set_tcp(1300) # # Send a v4 TCP SYN packet that will be translated and MSS clamped # p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) p_ip4 = IP(src=self.pg0.remote_ip4, dst='192.168.0.1') payload = TCP(sport=0xabcd, dport=0xabcd, flags="S", options=[('MSS', 1460)]) p4 = (p_ether / p_ip4 / payload) p6_translated = (IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1f0::c0a8:1:f") / payload) p6_translated.hlim -= 1 p6_translated[TCP].options = [('MSS', 1300)] rx = self.send_and_expect(self.pg0, p4 * 1, self.pg1) for p in rx: self.validate(p[1], p6_translated) # Send back an IPv6 packet that will be "untranslated" p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) p_ip6 = IPv6(src='2001:db8:1f0::c0a8:1:f', dst='1234:5678:90ab:cdef:ac:1001:200:0') p6 = (p_ether6 / p_ip6 / payload) p4_translated = (IP(src='192.168.0.1', dst=self.pg0.remote_ip4) / payload) p4_translated.id = 0 p4_translated.ttl -= 1 p4_translated[TCP].options = [('MSS', 1300)] rx = self.send_and_expect(self.pg1, p6 * 1, self.pg0) for p in rx: self.validate(p[1], p4_translated)
def test_map_e(self): """ MAP-E """ # # Add a route to the MAP-BR # map_br_pfx = "2001::" map_br_pfx_len = 32 map_route = VppIpRoute( self, map_br_pfx, map_br_pfx_len, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)]) map_route.add_vpp_config() # # Add a domain that maps from pg0 to pg1 # map_dst = '2001::/32' map_src = '3000::1/128' client_pfx = '192.168.0.0/16' map_translated_addr = '2001:0:101:7000:0:c0a8:101:7' tag = 'MAP-E tag.' self.vapi.map_add_domain(ip4_prefix=client_pfx, ip6_prefix=map_dst, ip6_src=map_src, ea_bits_len=20, psid_offset=4, psid_length=4, tag=tag) self.vapi.map_param_set_security_check(enable=1, fragments=1) # Enable MAP on interface. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0) # Ensure MAP doesn't steal all packets! v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) / UDP(sport=20000, dport=10000) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg0, v4 * 1, self.pg0) v4_reply = v4[1] v4_reply.ttl -= 1 for p in rx: self.validate(p[1], v4_reply) # # Fire in a v4 packet that will be encapped to the BR # v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw(b'\xa5' * 100)) self.send_and_assert_encapped_one(v4, "3000::1", map_translated_addr) # # Verify reordered fragments are able to pass as well # v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(id=1, src=self.pg0.remote_ip4, dst='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw(b'\xa5' * 1000)) frags = fragment_rfc791(v4, 400) frags.reverse() self.send_and_assert_encapped(frags, "3000::1", map_translated_addr) # Enable MAP on interface. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=0) # Ensure MAP doesn't steal all packets v6 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6) / UDP(sport=20000, dport=10000) / Raw(b'\xa5' * 100)) rx = self.send_and_expect(self.pg1, v6 * 1, self.pg1) v6_reply = v6[1] v6_reply.hlim -= 1 for p in rx: self.validate(p[1], v6_reply) # # Fire in a V6 encapped packet. # expect a decapped packet on the inside ip4 link # p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(dst='3000::1', src=map_translated_addr) / IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / UDP(sport=10000, dport=20000) / Raw(b'\xa5' * 100)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) rx = rx[0] self.assertFalse(rx.haslayer(IPv6)) self.assertEqual(rx[IP].src, p[IP].src) self.assertEqual(rx[IP].dst, p[IP].dst) # # Verify encapped reordered fragments pass as well # p = (IP(id=1, dst=self.pg0.remote_ip4, src='192.168.1.1') / UDP(sport=10000, dport=20000) / Raw(b'\xa5' * 1500)) frags = fragment_rfc791(p, 400) frags.reverse() stream = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(dst='3000::1', src=map_translated_addr) / x for x in frags) self.pg1.add_stream(stream) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(len(frags)) for r in rx: self.assertFalse(r.haslayer(IPv6)) self.assertEqual(r[IP].src, p[IP].src) self.assertEqual(r[IP].dst, p[IP].dst) # Verify that fragments pass even if ipv6 layer is fragmented stream = (IPv6(dst='3000::1', src=map_translated_addr) / x for x in frags) v6_stream = [ Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / x for i in range(len(frags)) for x in fragment_rfc8200( IPv6(dst='3000::1', src=map_translated_addr) / frags[i], i, 200) ] self.pg1.add_stream(v6_stream) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(len(frags)) for r in rx: self.assertFalse(r.haslayer(IPv6)) self.assertEqual(r[IP].src, p[IP].src) self.assertEqual(r[IP].dst, p[IP].dst) # # Pre-resolve. No API for this!! # self.vapi.ppcli("map params pre-resolve ip6-nh 4001::1") self.send_and_assert_no_replies(self.pg0, v4, "resolved via default route") # # Add a route to 4001::1. Expect the encapped traffic to be # sent via that routes next-hop # pre_res_route = VppIpRoute( self, "4001::1", 128, [VppRoutePath(self.pg1.remote_hosts[2].ip6, self.pg1.sw_if_index)]) pre_res_route.add_vpp_config() self.send_and_assert_encapped_one(v4, "3000::1", map_translated_addr, dmac=self.pg1.remote_hosts[2].mac) # # change the route to the pre-solved next-hop # pre_res_route.modify( [VppRoutePath(self.pg1.remote_hosts[3].ip6, self.pg1.sw_if_index)]) pre_res_route.add_vpp_config() self.send_and_assert_encapped_one(v4, "3000::1", map_translated_addr, dmac=self.pg1.remote_hosts[3].mac) # # cleanup. The test infra's object registry will ensure # the route is really gone and thus that the unresolve worked. # pre_res_route.remove_vpp_config() self.vapi.ppcli("map params pre-resolve del ip6-nh 4001::1")
def test_map_e_inner_frag(self): """ MAP-E Inner fragmentation """ # # Add a route to the MAP-BR # map_br_pfx = "2001::" map_br_pfx_len = 32 map_route = VppIpRoute( self, map_br_pfx, map_br_pfx_len, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)]) map_route.add_vpp_config() # # Add a domain that maps from pg0 to pg1 # map_dst = '2001::/32' map_src = '3000::1/128' client_pfx = '192.168.0.0/16' map_translated_addr = '2001:0:101:7000:0:c0a8:101:7' tag = 'MAP-E tag.' self.vapi.map_add_domain(ip4_prefix=client_pfx, ip6_prefix=map_dst, ip6_src=map_src, ea_bits_len=20, psid_offset=4, psid_length=4, mtu=1000, tag=tag) # Enable MAP on interface. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0) # Enable inner fragmentation self.vapi.map_param_set_fragmentation(inner=1) v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw(b'\xa5' * 1300)) self.pg_send(self.pg0, v4 * 1) rx = self.pg1.get_capture(2) frags = fragment_rfc791(v4[1], 1000) frags[0].id = 0 frags[1].id = 0 frags[0].ttl -= 1 frags[1].ttl -= 1 frags[0].chksum = 0 frags[1].chksum = 0 v6_reply1 = (IPv6(src='3000::1', dst=map_translated_addr, hlim=63) / frags[0]) v6_reply2 = (IPv6(src='3000::1', dst=map_translated_addr, hlim=63) / frags[1]) rx[0][1].fl = 0 rx[1][1].fl = 0 rx[0][1][IP].id = 0 rx[1][1][IP].id = 0 rx[0][1][IP].chksum = 0 rx[1][1][IP].chksum = 0 self.validate(rx[0][1], v6_reply1) self.validate(rx[1][1], v6_reply2)
def gen_pkts6(self, sw_intf, src, dst, count=1, payload_size=100): return [ Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) / IPv6(src=src, dst=dst) / UDP(sport=1166, dport=2233) / Raw(b'X' * payload_size) for i in range(count) ]
def send_full_chlo_to_existing_connection(self): """ Is it sent encrypted? :return: """ try: previous_session = SessionModel.get(SessionModel.id == 1) self.logger.info(previous_session) self.logger.info("Server config Id {}".format( previous_session.server_config_id)) self.logger.info(SessionInstance.get_instance().app_keys) SessionInstance.get_instance( ).last_received_rej = "-1" # I want to force the sniffer to generate a new set of keys. SessionInstance.get_instance().zero_rtt = True # The order is important! tags = [ { 'name': 'PAD', 'value': '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' }, { 'name': 'SNI', 'value': '7777772e6578616d706c652e6f7267' }, { 'name': 'STK', 'value': previous_session.source_address_token }, { 'name': 'SNO', 'value': previous_session.server_nonce }, { 'name': 'VER', 'value': '00000000' }, { 'name': 'CCS', 'value': '01e8816092921ae87eed8086a2158291' }, { 'name': 'NONC', 'value': '5ac349e90091b5556f1a3c52eb57f92c12640e876e26ab2601c02b2a32f54830' }, { 'name': 'AEAD', 'value': '41455347' # AESGCM12 }, { 'name': 'SCID', 'value': previous_session.server_config_id }, { 'name': 'PDMD', 'value': '58353039' }, { 'name': 'ICSL', 'value': '1e000000' }, { 'name': 'PUBS', 'value': '96D49F2CE98F31F053DCB6DFE729669385E5FD99D5AA36615E1A9AD57C1B090C' }, { 'name': 'MIDS', 'value': '64000000' }, { 'name': 'KEXS', 'value': '43323535' # C25519 }, { 'name': 'XLCT', 'value': '8d884a6c79a0e6de' }, { 'name': 'CFCW', 'value': '00c00000' }, { 'name': 'SFCW', 'value': '00800000' }, ] d = DynamicCHLOPacket(tags) body = d.build_body() PacketNumberInstance.get_instance().reset() conn_id = random.getrandbits(64) SessionInstance.get_instance( ).server_nonce = previous_session.server_nonce SessionInstance.get_instance().connection_id_as_number = conn_id SessionInstance.get_instance().connection_id = str( format(conn_id, 'x').zfill(8)) SessionInstance.get_instance().peer_public_value = bytes.fromhex( previous_session.public_value) self.logger.info("Using connection Id {}".format( SessionInstance.get_instance().connection_id)) SessionInstance.get_instance().shlo_received = False # SessionInstance.get_instance().zero_rtt = True # This one should only be set if the Zero RTT CHLO does not result in a REJ. # a = FullCHLOPacketNoPadding() a.setfieldval( 'Packet Number', PacketNumberInstance.get_instance().get_next_packet_number()) a.setfieldval( 'CID', string_to_ascii(SessionInstance.get_instance().connection_id)) # # Lets just create the public key for DHKE dhke.set_up_my_keys() associated_data = extract_from_packet(a, end=15) body_mah = [body[i:i + 2] for i in range(0, len(body), 2)] message_authentication_hash = FNV128A().generate_hash( associated_data, body_mah) conf.L3socket = L3RawSocket SessionInstance.get_instance( ).chlo = extract_from_packet_as_bytestring( a, start=27 ) # CHLO from the CHLO tag, which starts at offset 26 (22 header + frame type + stream id + offset) SessionInstance.get_instance().chlo += body[4:] # dhke.generate_keys(bytes.fromhex(previous_session.public_value), False) # ciphertext = CryptoManager.encrypt(bytes.fromhex(SessionInstance.get_instance().chlo), 1) # a.setfieldval('Message Authentication Hash', string_to_ascii(message_authentication_hash)) # # print("Send full CHLO from existing connection") # p = IP(dst=SessionInstance.get_instance().destination_ip) / UDP( dport=6121, sport=61250) / a / Raw(load=string_to_ascii(body)) # # Maybe we cannot assume that is just a version negotiation packet? self.sniffer.add_observer(self) send(p) self.wait_for_signal_or_expiration() self.processed = False self.sniffer.remove_observer(self) except Exception: self.send_chlo(False)
def send_ack_for_encrypted_message(self): ack = AckNotificationPacket() conf.L3socket = L3RawSocket ack.setfieldval( 'CID', string_to_ascii(SessionInstance.get_instance().connection_id)) next_packet_number_int = PacketNumberInstance.get_instance( ).get_next_packet_number() next_packet_number_byte = int(next_packet_number_int).to_bytes( 8, byteorder='little') next_packet_number_nonce = int(next_packet_number_int).to_bytes( 2, byteorder='big') # print("Sending encrypted ack for packet number {}".format(next_packet_number_int)) ack.setfieldval("Packet Number", next_packet_number_int) highest_received_packet_number = format( int( PacketNumberInstance.get_instance(). get_highest_received_packet_number(), 16), 'x') ack_body = "40" ack_body += str(highest_received_packet_number).zfill(2) ack_body += "0062" ack_body += str(highest_received_packet_number).zfill(2) ack_body += "00" # not sure yet if we can remove this? keys = SessionInstance.get_instance().keys request = { 'mode': 'encryption', 'input': ack_body, 'key': keys['key1'].hex(), # For encryption, we use my key 'additionalData': "18" + SessionInstance.get_instance().connection_id + next_packet_number_byte.hex() [:4], # Fixed public flags 18 || fixed connection Id || packet number 'nonce': keys['iv1'].hex() + next_packet_number_nonce.hex().ljust(16, '0') } # print("Ack request for encryption {}".format(request)) ciphertext = CryptoConnectionManager.send_message( ConnectionEndpoint.CRYPTO_ORACLE, json.dumps(request).encode('utf-8'), True) ciphertext = ciphertext['data'] # print("Ciphertext in ack {}".format(ciphertext)) ack.setfieldval("Message Authentication Hash", string_to_ascii(ciphertext[:24])) SessionInstance.get_instance().nr_ack_send += 1 p = IP(dst=SessionInstance.get_instance().destination_ip) / UDP( dport=6121, sport=61250) / ack / Raw(load=string_to_ascii(ciphertext[24:])) send(p)
def test_map_e(self): """ MAP-E """ # # Add a route to the MAP-BR # map_br_pfx = "2001::" map_br_pfx_len = 64 map_route = VppIpRoute(self, map_br_pfx, map_br_pfx_len, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) map_route.add_vpp_config() # # Add a domain that maps from pg0 to pg1 # map_dst = '2001::/64' map_src = '3000::1/128' client_pfx = '192.168.0.0/16' self.vapi.map_add_domain(map_dst, client_pfx, map_src) # Enable MAP on interface. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg0.sw_if_index, is_translation=0) # Ensure MAP doesn't steal all packets! v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg0, v4*1, self.pg0) v4_reply = v4[1] v4_reply.ttl -= 1 for p in rx: self.validate(p[1], v4_reply) # # Fire in a v4 packet that will be encapped to the BR # v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) self.send_and_assert_encapped(v4, "3000::1", "2001::c0a8:0:0") # Enable MAP on interface. self.vapi.map_if_enable_disable(is_enable=1, sw_if_index=self.pg1.sw_if_index, is_translation=0) # Ensure MAP doesn't steal all packets v6 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6) / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) rx = self.send_and_expect(self.pg1, v6*1, self.pg1) v6_reply = v6[1] v6_reply.hlim -= 1 for p in rx: self.validate(p[1], v6_reply) # # Fire in a V6 encapped packet. # expect a decapped packet on the inside ip4 link # p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(dst='3000::1', src="2001::1") / IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) rx = rx[0] self.assertFalse(rx.haslayer(IPv6)) self.assertEqual(rx[IP].src, p[IP].src) self.assertEqual(rx[IP].dst, p[IP].dst) # # Pre-resolve. No API for this!! # self.vapi.ppcli("map params pre-resolve ip6-nh 4001::1") self.send_and_assert_no_replies(self.pg0, v4, "resovled via default route") # # Add a route to 4001::1. Expect the encapped traffic to be # sent via that routes next-hop # pre_res_route = VppIpRoute( self, "4001::1", 128, [VppRoutePath(self.pg1.remote_hosts[2].ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) pre_res_route.add_vpp_config() self.send_and_assert_encapped(v4, "3000::1", "2001::c0a8:0:0", dmac=self.pg1.remote_hosts[2].mac) # # change the route to the pre-solved next-hop # pre_res_route.modify([VppRoutePath(self.pg1.remote_hosts[3].ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)]) pre_res_route.add_vpp_config() self.send_and_assert_encapped(v4, "3000::1", "2001::c0a8:0:0", dmac=self.pg1.remote_hosts[3].mac) # # cleanup. The test infra's object registry will ensure # the route is really gone and thus that the unresolve worked. # pre_res_route.remove_vpp_config() self.vapi.ppcli("map params pre-resolve del ip6-nh 4001::1")
def test_igmp_host(self): """ IGMP Host functions """ # # Enable interface for host functions # self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 1, IGMP_MODE.HOST) # # Add one S,G of state and expect a state-change event report # indicating the addition of the S,G # h1 = self.add_group(self.pg0, IgmpSG("239.1.1.1", ["1.1.1.1"])) # search for the corresponding state created in VPP dump = self.vapi.igmp_dump(self.pg0.sw_if_index) self.assertEqual(len(dump), 1) self.assertTrue(find_igmp_state(dump, self.pg0, "239.1.1.1", "1.1.1.1")) # # Send a general query (to the all router's address) # expect VPP to respond with a membership report. # Pad the query with 0 - some devices in the big wild # internet are prone to this. # p_g = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='224.0.0.1', tos=0xc0) / IGMPv3(type="Membership Query", mrcode=100) / IGMPv3mq(gaddr="0.0.0.0") / Raw('\x00' * 10)) self.send(self.pg0, p_g) capture = self.pg0.get_capture(1, timeout=10) self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")]) # # Group specific query # p_gs = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, options=[IPOption(copy_flag=1, optclass="control", option="router_alert")]) / IGMPv3(type="Membership Query", mrcode=100) / IGMPv3mq(gaddr="239.1.1.1")) self.send(self.pg0, p_gs) capture = self.pg0.get_capture(1, timeout=10) self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")]) # # A group and source specific query, with the source matching # the source VPP has # p_gs1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, options=[IPOption(copy_flag=1, optclass="control", option="router_alert")]) / IGMPv3(type="Membership Query", mrcode=100) / IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.1"])) self.send(self.pg0, p_gs1) capture = self.pg0.get_capture(1, timeout=10) self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")]) # # A group and source specific query that reports more sources # than the packet actually has. # p_gs2 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, options=[IPOption(copy_flag=1, optclass="control", option="router_alert")]) / IGMPv3(type="Membership Query", mrcode=100) / IGMPv3mq(gaddr="239.1.1.1", numsrc=4, srcaddrs=["1.1.1.1"])) self.send_and_assert_no_replies(self.pg0, p_gs2, timeout=10) # # A group and source specific query, with the source NOT matching # the source VPP has. There should be no response. # p_gs2 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, options=[IPOption(copy_flag=1, optclass="control", option="router_alert")]) / IGMPv3(type="Membership Query", mrcode=100) / IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.2"])) self.send_and_assert_no_replies(self.pg0, p_gs2, timeout=10) # # A group and source specific query, with the multiple sources # one of which matches the source VPP has. # The report should contain only the source VPP has. # p_gs3 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, options=[IPOption(copy_flag=1, optclass="control", option="router_alert")]) / IGMPv3(type="Membership Query", mrcode=100) / IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.1", "1.1.1.2", "1.1.1.3"])) self.send(self.pg0, p_gs3) capture = self.pg0.get_capture(1, timeout=10) self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")]) # # Two source and group specific queries in quick succession, the # first does not have VPPs source the second does. then vice-versa # self.send(self.pg0, [p_gs2, p_gs1]) capture = self.pg0.get_capture(1, timeout=10) self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")]) self.send(self.pg0, [p_gs1, p_gs2]) capture = self.pg0.get_capture(1, timeout=10) self.verify_report(capture[0], [IgmpRecord(h1.sg, "Mode Is Include")]) # # remove state, expect the report for the removal # self.remove_group(h1) dump = self.vapi.igmp_dump() self.assertFalse(dump) # # A group with multiple sources # h2 = self.add_group(self.pg0, IgmpSG("239.1.1.1", ["1.1.1.1", "1.1.1.2", "1.1.1.3"])) # search for the corresponding state created in VPP dump = self.vapi.igmp_dump(self.pg0.sw_if_index) self.assertEqual(len(dump), 3) for s in h2.sg.saddrs: self.assertTrue(find_igmp_state(dump, self.pg0, "239.1.1.1", s)) # # Send a general query (to the all router's address) # expect VPP to respond with a membership report will all sources # self.send(self.pg0, p_g) capture = self.pg0.get_capture(1, timeout=10) self.verify_report(capture[0], [IgmpRecord(h2.sg, "Mode Is Include")]) # # Group and source specific query; some present some not # p_gs = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, options=[IPOption(copy_flag=1, optclass="control", option="router_alert")]) / IGMPv3(type="Membership Query", mrcode=100) / IGMPv3mq(gaddr="239.1.1.1", srcaddrs=["1.1.1.1", "1.1.1.2", "1.1.1.4"])) self.send(self.pg0, p_gs) capture = self.pg0.get_capture(1, timeout=10) self.verify_report(capture[0], [IgmpRecord( IgmpSG('239.1.1.1', ["1.1.1.1", "1.1.1.2"]), "Mode Is Include")]) # # add loads more groups # h3 = self.add_group(self.pg0, IgmpSG("239.1.1.2", ["2.1.1.1", "2.1.1.2", "2.1.1.3"])) h4 = self.add_group(self.pg0, IgmpSG("239.1.1.3", ["3.1.1.1", "3.1.1.2", "3.1.1.3"])) h5 = self.add_group(self.pg0, IgmpSG("239.1.1.4", ["4.1.1.1", "4.1.1.2", "4.1.1.3"])) h6 = self.add_group(self.pg0, IgmpSG("239.1.1.5", ["5.1.1.1", "5.1.1.2", "5.1.1.3"])) h7 = self.add_group(self.pg0, IgmpSG("239.1.1.6", ["6.1.1.1", "6.1.1.2", "6.1.1.3", "6.1.1.4", "6.1.1.5", "6.1.1.6", "6.1.1.7", "6.1.1.8", "6.1.1.9", "6.1.1.10", "6.1.1.11", "6.1.1.12", "6.1.1.13", "6.1.1.14", "6.1.1.15", "6.1.1.16"])) # # general query. # the order the groups come in is not important, so what is # checked for is what VPP is sending today. # self.send(self.pg0, p_g) capture = self.pg0.get_capture(1, timeout=10) self.verify_report(capture[0], [IgmpRecord(h3.sg, "Mode Is Include"), IgmpRecord(h2.sg, "Mode Is Include"), IgmpRecord(h6.sg, "Mode Is Include"), IgmpRecord(h4.sg, "Mode Is Include"), IgmpRecord(h5.sg, "Mode Is Include"), IgmpRecord(h7.sg, "Mode Is Include")]) # # modify a group to add and remove some sources # h7.sg = IgmpSG("239.1.1.6", ["6.1.1.1", "6.1.1.2", "6.1.1.5", "6.1.1.6", "6.1.1.7", "6.1.1.8", "6.1.1.9", "6.1.1.10", "6.1.1.11", "6.1.1.12", "6.1.1.13", "6.1.1.14", "6.1.1.15", "6.1.1.16", "6.1.1.17", "6.1.1.18"]) self.pg_enable_capture(self.pg_interfaces) self.pg_start() h7.add_vpp_config() capture = self.pg0.get_capture(1, timeout=10) self.verify_report(capture[0], [IgmpRecord(IgmpSG("239.1.1.6", ["6.1.1.17", "6.1.1.18"]), "Allow New Sources"), IgmpRecord(IgmpSG("239.1.1.6", ["6.1.1.3", "6.1.1.4"]), "Block Old Sources")]) # # add an additional groups with many sources so that each group # consumes the link MTU. We should therefore see multiple state # state reports when queried. # self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [560, 0, 0, 0]) src_list = [] for i in range(128): src_list.append("10.1.1.%d" % i) h8 = self.add_group(self.pg0, IgmpSG("238.1.1.1", src_list)) h9 = self.add_group(self.pg0, IgmpSG("238.1.1.2", src_list)) self.send(self.pg0, p_g) capture = self.pg0.get_capture(4, timeout=10) self.verify_report(capture[0], [IgmpRecord(h3.sg, "Mode Is Include"), IgmpRecord(h2.sg, "Mode Is Include"), IgmpRecord(h6.sg, "Mode Is Include"), IgmpRecord(h4.sg, "Mode Is Include"), IgmpRecord(h5.sg, "Mode Is Include")]) self.verify_report(capture[1], [IgmpRecord(h8.sg, "Mode Is Include")]) self.verify_report(capture[2], [IgmpRecord(h7.sg, "Mode Is Include")]) self.verify_report(capture[3], [IgmpRecord(h9.sg, "Mode Is Include")]) # # drop the MTU further (so a 128 sized group won't fit) # self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [512, 0, 0, 0]) self.pg_enable_capture(self.pg_interfaces) self.pg_start() h10 = VppHostState(self, IGMP_FILTER.INCLUDE, self.pg0.sw_if_index, IgmpSG("238.1.1.3", src_list)) h10.add_vpp_config() capture = self.pg0.get_capture(2, timeout=10) # # remove state, expect the report for the removal # the dump should be empty # self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [600, 0, 0, 0]) self.remove_group(h8) self.remove_group(h9) self.remove_group(h2) self.remove_group(h3) self.remove_group(h4) self.remove_group(h5) self.remove_group(h6) self.remove_group(h7) self.remove_group(h10) self.logger.info(self.vapi.cli("sh igmp config")) self.assertFalse(self.vapi.igmp_dump()) # # TODO # ADD STATE ON MORE INTERFACES # self.vapi.igmp_enable_disable(self.pg0.sw_if_index, 0, IGMP_MODE.HOST)
def test_map_e(self): """ MAP-E """ # # Add a route to the MAP-BR # map_br_pfx = "2001::" map_br_pfx_len = 64 map_route = VppIpRoute(self, map_br_pfx, map_br_pfx_len, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) map_route.add_vpp_config() # # Add a domain that maps from pg0 to pg1 # map_dst = socket.inet_pton(socket.AF_INET6, map_br_pfx) map_src = "3001::1" map_src_n = socket.inet_pton(socket.AF_INET6, map_src) client_pfx = socket.inet_pton(socket.AF_INET, "192.168.0.0") self.vapi.map_add_domain(map_dst, map_br_pfx_len, map_src_n, 128, client_pfx, 16) # # Fire in a v4 packet that will be encapped to the BR # v4 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) self.send_and_assert_encapped(v4, map_src, "2001::c0a8:0:0") # # Fire in a V6 encapped packet. # expect a decapped packet on the inside ip4 link # p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(dst=map_src, src="2001::1") / IP(dst=self.pg0.remote_ip4, src='192.168.1.1') / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) rx = rx[0] self.assertFalse(rx.haslayer(IPv6)) self.assertEqual(rx[IP].src, p[IP].src) self.assertEqual(rx[IP].dst, p[IP].dst) # # Pre-resolve. No API for this!! # self.vapi.ppcli("map params pre-resolve ip6-nh 4001::1") self.send_and_assert_no_replies(self.pg0, v4, "resovled via default route") # # Add a route to 4001::1. Expect the encapped traffic to be # sent via that routes next-hop # pre_res_route = VppIpRoute( self, "4001::1", 128, [VppRoutePath(self.pg1.remote_hosts[2].ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) pre_res_route.add_vpp_config() self.send_and_assert_encapped(v4, map_src, "2001::c0a8:0:0", dmac=self.pg1.remote_hosts[2].mac) # # change the route to the pre-solved next-hop # pre_res_route.modify([VppRoutePath(self.pg1.remote_hosts[3].ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)]) pre_res_route.add_vpp_config() self.send_and_assert_encapped(v4, map_src, "2001::c0a8:0:0", dmac=self.pg1.remote_hosts[3].mac) # # cleanup. The test infra's object registry will ensure # the route is really gone and thus that the unresolve worked. # pre_res_route.remove_vpp_config() self.vapi.ppcli("map params pre-resolve del ip6-nh 4001::1")
def frame_pg1_to_pg0(self): """ Ethernet frame sent from pg1 and expected to arrive at pg0 """ return (Ether(src='00:00:00:00:00:02', dst='00:00:00:00:00:01') / IP(src='4.3.2.1', dst='1.2.3.4') / UDP(sport=20000, dport=10000) / Raw('\xa5' * 100))
def gen_pkts(self, sw_intf, src, dst, count=1, payload_size=100): return [ Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1144, dport=2233) / Raw('X' * payload_size) for i in range(count) ]