def test_long_fragment_chain(self): """ long fragment chain """ error_cnt_str = \ "/err/ip6-reassembly-feature/fragment chain too long (drop)" error_cnt = self.statistics.get_err_counter(error_cnt_str) self.vapi.ip_reassembly_set(timeout_ms=100, max_reassemblies=1000, max_reassembly_length=3, expire_walk_interval_ms=50, is_ip6=1) p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / UDP(sport=1234, dport=5678) / Raw("X" * 1000)) frags = fragment_rfc8200(p, 1, 300) + fragment_rfc8200(p, 2, 500) self.pg_enable_capture() self.src_if.add_stream(frags) self.pg_start() self.dst_if.get_capture(1) self.assert_error_counter_equal(error_cnt_str, error_cnt + 1)
def create_fragments(cls): infos = cls._packet_infos cls.pkt_infos = [] for index, info in six.iteritems(infos): p = info.data # cls.logger.debug(ppp("Packet:", p.__class__(str(p)))) fragments_400 = fragment_rfc8200(p, info.index, 400) fragments_300 = fragment_rfc8200(p, info.index, 300) cls.pkt_infos.append((index, fragments_400, fragments_300)) cls.fragments_400 = [x for _, frags, _ in cls.pkt_infos for x in frags] cls.fragments_300 = [x for _, _, frags in cls.pkt_infos for x in frags] cls.logger.debug( "Fragmented %s packets into %s 400-byte fragments, " "and %s 300-byte fragments" % (len(infos), len(cls.fragments_400), len(cls.fragments_300)))
def verify_tun_reass_66(self, p): self.vapi.cli("clear errors") self.vapi.ip_reassembly_enable_disable( sw_if_index=self.tun_if.sw_if_index, enable_ip6=True) try: config_tun_params(p, self.encryption_type, self.tun_if) send_pkts = self.gen_encrypt_pkts6(p.scapy_tun_sa, self.tun_if, src=p.remote_tun_if_host, dst=self.pg1.remote_ip6, count=1, payload_size=1900) send_pkts = fragment_rfc8200(send_pkts[0], 1, 1400, self.logger) recv_pkts = self.send_and_expect(self.tun_if, send_pkts, self.pg1, n_rx=1) self.verify_decrypted6(p, recv_pkts) send_pkts = self.gen_pkts6(self.pg1, src=self.pg1.remote_ip6, dst=p.remote_tun_if_host, count=1, payload_size=64) recv_pkts = self.send_and_expect(self.pg1, send_pkts, self.tun_if) self.verify_encrypted6(p, p.vpp_tun_sa, recv_pkts) finally: self.logger.info(self.vapi.ppcli("show error")) self.logger.info(self.vapi.ppcli("show ipsec all")) self.verify_counters6(p, p, 1) self.vapi.ip_reassembly_enable_disable( sw_if_index=self.tun_if.sw_if_index, enable_ip6=False)
def create_fragments(cls): infos = cls._packet_infos cls.pkt_infos = [] for index, info in six.iteritems(infos): p = info.data # cls.logger.debug(ppp("Packet:", # p.__class__(scapy.compat.raw(p)))) fragments_400 = fragment_rfc8200(p, info.index, 400) fragments_300 = fragment_rfc8200(p, info.index, 300) cls.pkt_infos.append((index, fragments_400, fragments_300)) cls.fragments_400 = [ x for _, frags, _ in cls.pkt_infos for x in frags] cls.fragments_300 = [ x for _, _, frags in cls.pkt_infos for x in frags] cls.logger.debug("Fragmented %s packets into %s 400-byte fragments, " "and %s 300-byte fragments" % (len(infos), len(cls.fragments_400), len(cls.fragments_300)))
def test_invalid_packet_size(self): """ total packet size > 65535 """ p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6) / UDP(sport=1234, dport=5678) / Raw()) self.extend_packet(p, 1000, self.padding) fragments = fragment_rfc8200(p, 1, 500) bad_fragment = fragments[1] bad_fragment[IPv6ExtHdrFragment].offset = 65500 self.pg_enable_capture() self.src_if.add_stream([bad_fragment]) self.pg_start() pkts = self.src_if.get_capture(expected_count=1) icmp = pkts[0] self.assertIn(ICMPv6ParamProblem, icmp) self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
def test_invalid_frag_size(self): """ fragment size not a multiple of 8 """ p = (Ether(dst=self.pg_if.local_mac, src=self.pg_if.remote_mac) / IPv6(src=self.pg_if.remote_ip6, dst=self.pg_if.local_ip6) / UDP(sport=1234, dport=self.punt_port) / Raw()) self.extend_packet(p, 1000, self.padding) fragments = fragment_rfc8200(p, 1, 500) bad_fragment = fragments[0] self.extend_packet(bad_fragment, len(bad_fragment) + 5) self.pg_enable_capture() self.pg_if.add_stream([bad_fragment]) self.pg_start() pkts = self.pg_if.get_capture(expected_count=1) icmp = pkts[0] self.assertIn(ICMPv6ParamProblem, icmp) self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
def test_missing_upper(self): """ missing upper layer """ p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6) / UDP(sport=1234, dport=5678) / Raw()) self.extend_packet(p, 1000, self.padding) fragments = fragment_rfc8200(p, 1, 500) bad_fragment = p.__class__(scapy.compat.raw(fragments[1])) bad_fragment[IPv6ExtHdrFragment].nh = 59 bad_fragment[IPv6ExtHdrFragment].offset = 0 self.pg_enable_capture() self.src_if.add_stream([bad_fragment]) self.pg_start() pkts = self.src_if.get_capture(expected_count=1) icmp = pkts[0] self.assertIn(ICMPv6ParamProblem, icmp) self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code")
def test_invalid_packet_size(self): """ total packet size > 65535 """ p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6) / UDP(sport=1234, dport=5678) / Raw()) self.extend_packet(p, 1000, self.padding) fragments = fragment_rfc8200(p, 1, 500) bad_fragment = fragments[1] bad_fragment[IPv6ExtHdrFragment].offset = 65500 self.pg_enable_capture() self.src_if.add_stream([bad_fragment]) self.pg_start() pkts = self.src_if.get_capture(expected_count=1) icmp = pkts[0] self.assertIn(ICMPv6ParamProblem, icmp) self.assert_equal(icmp[ICMPv6ParamProblem].code, 0, "ICMP code")
def test_missing_upper(self): """ missing upper layer """ p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6) / UDP(sport=1234, dport=5678) / Raw()) self.extend_packet(p, 1000, self.padding) fragments = fragment_rfc8200(p, 1, 500) bad_fragment = p.__class__(scapy.compat.raw(fragments[1])) bad_fragment[IPv6ExtHdrFragment].nh = 59 bad_fragment[IPv6ExtHdrFragment].offset = 0 self.pg_enable_capture() self.src_if.add_stream([bad_fragment]) self.pg_start() pkts = self.src_if.get_capture(expected_count=1) icmp = pkts[0] self.assertIn(ICMPv6ParamProblem, icmp) self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code")
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_fif6(self): """ Fragments in fragments (6o6) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip6 = "1002::1" self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6) self.gre6.add_vpp_config() self.gre6.admin_up() self.gre6.config_ip6() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.gre6.sw_if_index, enable_ip6=True) self.route6 = VppIpRoute(self, self.tun_ip6, 128, [ VppRoutePath(self.src_if.remote_ip6, self.src_if.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) self.route6.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.src_if, self.dst_if) payload = self.info_to_payload(info) # Ethernet header here is only for size calculation, thus it # doesn't matter how it's initialized. This is to ensure that # reassembled packet is not > 9000 bytes, so that it's not dropped p = (Ether() / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / UDP(sport=1234, dport=5678) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p[IPv6] # use only IPv6 part, without ethernet header fragments = [ x for _, i in six.iteritems(self._packet_infos) for x in fragment_rfc8200(i.data, i.index, 400) ] encapped_fragments = \ [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in ( fragment_rfc8200( p, 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id, 200) if IPv6ExtHdrFragment in p else [p] ) ] self.src_if.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.src_if.assert_nothing_captured() packets = self.dst_if.get_capture(len(self._packet_infos)) self.verify_capture(packets, IPv6) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre6.remove_vpp_config()
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=0 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) # IPv4 TTL=1 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=1) / 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 at BR ip6_hlim_expired = IPv6( hlim=1, 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=1, ) / payload) rx = self.send_and_expect(self.pg1, p6 * 1, self.pg1) for p in rx: self.validate(p[1], icmp6_reply) # IPv6 Hop limit beyond BR 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) # UDP packet fragmentation payload_len = 1453 payload = UDP(sport=40000, dport=4000) / self.payload(payload_len) p4 = p_ether / p_ip4 / payload self.pg_enable_capture() self.pg0.add_stream(p4) self.pg_start() rx = self.pg1.get_capture(2) p_ip6_translated = IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:1e0::c0a8:1:e") for p in rx: self.validate_frag6(p, p_ip6_translated) self.validate_frag_payload_len6(rx, UDP, payload_len) # UDP packet fragmentation send fragments payload_len = 1453 payload = UDP(sport=40000, dport=4000) / self.payload(payload_len) p4 = p_ether / p_ip4 / payload frags = fragment_rfc791(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: self.validate_frag6(p, p_ip6_translated) self.validate_frag_payload_len6(rx, UDP, payload_len) # Send back an fragmented IPv6 UDP packet that will be "untranslated" payload = UDP(sport=4000, dport=40000) / self.payload(payload_len) p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) p_ip6 = IPv6(src="2001:db8:1e0::c0a8:1:e", dst="1234:5678:90ab:cdef:ac:1001:200:0") p6 = p_ether6 / p_ip6 / payload frags6 = fragment_rfc8200(p6, identification=0xDCBA, fragsize=1000) p_ip4_translated = IP(src="192.168.0.1", dst=self.pg0.remote_ip4) p4_translated = p_ip4_translated / payload p4_translated.id = 0 p4_translated.ttl -= 1 self.pg_enable_capture() self.pg1.add_stream(frags6) self.pg_start() rx = self.pg0.get_capture(2) for p in rx: self.validate_frag4(p, p4_translated) self.validate_frag_payload_len4(rx, UDP, payload_len) # ICMP packet fragmentation payload = ICMP(id=6529) / self.payload(payload_len) p4 = p_ether / p_ip4 / payload self.pg_enable_capture() self.pg0.add_stream(p4) self.pg_start() rx = self.pg1.get_capture(2) p_ip6_translated = IPv6(src="1234:5678:90ab:cdef:ac:1001:200:0", dst="2001:db8:160::c0a8:1:6") for p in rx: self.validate_frag6(p, p_ip6_translated) self.validate_frag_payload_len6(rx, ICMPv6EchoRequest, payload_len) # ICMP packet fragmentation send fragments payload = ICMP(id=6529) / self.payload(payload_len) p4 = p_ether / p_ip4 / payload frags = fragment_rfc791(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: self.validate_frag6(p, p_ip6_translated) self.validate_frag_payload_len6(rx, ICMPv6EchoRequest, payload_len) # 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) # TCP MSS clamping cleanup self.vapi.map_param_set_tcp(0) # Enable icmp6 param to get back ICMPv6 unreachable messages in case # of security check fails self.vapi.map_param_set_icmp6(enable_unreachable=1) # Send back an IPv6 packet that will be droppped due to security # check fail p_ether6 = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) p_ip6_sec_check_fail = IPv6(src="2001:db8:1fe::c0a8:1:f", dst="1234:5678:90ab:cdef:ac:1001:200:0") payload = TCP(sport=0xABCD, dport=0xABCD) p6 = p_ether6 / p_ip6_sec_check_fail / payload self.pg_send(self.pg1, p6 * 1) self.pg0.get_capture(0, timeout=1) rx = self.pg1.get_capture(1) icmp6_reply = (IPv6( hlim=255, src=self.pg1.local_ip6, dst="2001:db8:1fe::c0a8:1:f") / ICMPv6DestUnreach(code=5) / p_ip6_sec_check_fail / payload) for p in rx: self.validate(p[1], icmp6_reply) # ICMPv6 unreachable messages cleanup self.vapi.map_param_set_icmp6(enable_unreachable=0)
def test_fif6(self): """ Fragments in fragments (6o6) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip6 = "1002::1" self.gre6 = VppGreInterface(self, self.src_if.local_ip6, self.tun_ip6) self.gre6.add_vpp_config() self.gre6.admin_up() self.gre6.config_ip6() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.gre6.sw_if_index, enable_ip6=True) self.route6 = VppIpRoute(self, self.tun_ip6, 128, [VppRoutePath(self.src_if.remote_ip6, self.src_if.sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) self.route6.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.src_if, self.dst_if) payload = self.info_to_payload(info) # Ethernet header here is only for size calculation, thus it # doesn't matter how it's initialized. This is to ensure that # reassembled packet is not > 9000 bytes, so that it's not dropped p = (Ether() / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / UDP(sport=1234, dport=5678) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p[IPv6] # use only IPv6 part, without ethernet header fragments = [x for _, i in six.iteritems(self._packet_infos) for x in fragment_rfc8200( i.data, i.index, 400)] encapped_fragments = \ [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in ( fragment_rfc8200( p, 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id, 200) if IPv6ExtHdrFragment in p else [p] ) ] self.src_if.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.src_if.assert_nothing_captured() packets = self.dst_if.get_capture(len(self._packet_infos)) self.verify_capture(packets, IPv6) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre6.remove_vpp_config()
def test_fif6(self): """ Fragments in fragments (6o6) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip6 = "1002::1" self.gre6 = VppGre6Interface(self, self.pg0.local_ip6, self.tun_ip6) self.gre6.add_vpp_config() self.gre6.admin_up() self.gre6.config_ip6() self.route6 = VppIpRoute(self, self.tun_ip6, 128, [ VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) self.route6.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.pg0, self.pg0) payload = self.info_to_payload(info) p = (IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) / UDP(sport=1234, dport=self.punt_port) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p fragments = [ x for _, i in self._packet_infos.iteritems() for x in fragment_rfc8200(i.data, i.index, 400) ] encapped_fragments = \ [Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(src=self.tun_ip6, dst=self.pg0.local_ip6) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in ( fragment_rfc8200( p, 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id, 200) if IPv6ExtHdrFragment in p else [p] ) ] self.pg0.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.pg0.assert_nothing_captured() packets = self.punt6_socket.wait_for_packets(len(self._packet_infos)) self.verify_capture(packets, IPv6) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre6.remove_vpp_config()