From cd5a4a035c0c7a7ca9f915bee83abde085c05ad7 Mon Sep 17 00:00:00 2001 From: Alexander Chernavin Date: Thu, 12 Mar 2020 08:42:12 -0400 Subject: [PATCH] map: fix translation of icmp4 error messages ICMP error messages are translated to ICMPv6 error messages with erroneous destination address in the outer IPv6 header because sender port is used instead of receiver port. Both source and destination addresses in the inner IPv6 header are translated erroneously because source and destination addresses of the inner IPv4 header are getting zeroed during the translation. With this commit, use receiver port for translation and save addresses of the inner IPv4 header before translation of the inner header. Type: fix Change-Id: I1e93d54c1bbc154b401adcbb0fb661299655d01a Signed-off-by: Alexander Chernavin --- src/plugins/map/ip4_map_t.c | 12 ++++++---- src/plugins/map/test/test_map_br.py | 45 +++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/plugins/map/ip4_map_t.c b/src/plugins/map/ip4_map_t.c index 4c0dd629aa8..7d16d7aa455 100644 --- a/src/plugins/map/ip4_map_t.c +++ b/src/plugins/map/ip4_map_t.c @@ -92,14 +92,18 @@ ip4_to_ip6_set_inner_icmp_cb (vlib_buffer_t * b, ip4_header_t * ip4, ip6_header_t * ip6, void *arg) { icmp_to_icmp6_ctx_t *ctx = arg; + ip4_address_t old_src, old_dst; + + old_src.as_u32 = ip4->src_address.as_u32; + old_dst.as_u32 = ip4->dst_address.as_u32; //Note that the source address is within the domain //while the destination address is the one outside the domain - ip4_map_t_embedded_address (ctx->d, &ip6->dst_address, &ip4->dst_address); + ip4_map_t_embedded_address (ctx->d, &ip6->dst_address, &old_dst); ip6->src_address.as_u64[0] = - map_get_pfx_net (ctx->d, ip4->src_address.as_u32, ctx->recv_port); + map_get_pfx_net (ctx->d, old_src.as_u32, ctx->recv_port); ip6->src_address.as_u64[1] = - map_get_sfx_net (ctx->d, ip4->src_address.as_u32, ctx->recv_port); + map_get_sfx_net (ctx->d, old_src.as_u32, ctx->recv_port); return 0; } @@ -150,7 +154,7 @@ ip4_map_t_icmp (vlib_main_t * vm, vnet_buffer (p0)->map_t.map_domain_index); ip40 = vlib_buffer_get_current (p0); - ctx0.recv_port = ip4_get_port (ip40, 1); + ctx0.recv_port = ip4_get_port (ip40, 0); ctx0.d = d0; if (ctx0.recv_port == 0) { diff --git a/src/plugins/map/test/test_map_br.py b/src/plugins/map/test/test_map_br.py index db0a5fc00e3..631517e5d4e 100644 --- a/src/plugins/map/test/test_map_br.py +++ b/src/plugins/map/test/test_map_br.py @@ -11,9 +11,9 @@ from util import fragment_rfc791, fragment_rfc8200 import scapy.compat from scapy.layers.l2 import Ether from scapy.packet import Raw -from scapy.layers.inet import IP, UDP, ICMP, TCP +from scapy.layers.inet import IP, UDP, ICMP, TCP, IPerror, UDPerror from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded, IPv6ExtHdrFragment -from scapy.layers.inet6 import ICMPv6EchoRequest, ICMPv6EchoReply +from scapy.layers.inet6 import ICMPv6EchoRequest, ICMPv6EchoReply, IPerror6 class TestMAPBR(VppTestCase): @@ -332,6 +332,47 @@ class TestMAPBR(VppTestCase): self.assertEqual(rx_pkt[ICMPv6EchoReply].id, self.ipv6_udp_or_tcp_map_port) + # + # Translation of ICMP Time Exceeded v4 -> v6 direction + # Received packet should be translated into an IPv6 Time Exceeded. + # + + def test_map_t_time_exceeded_ip4_to_ip6(self): + """ MAP-T time exceeded IPv4 -> IPv6 """ + + eth = Ether(src=self.pg0.remote_mac, + dst=self.pg0.local_mac) + ip = IP(src=self.pg0.remote_ip4, + dst=self.ipv4_map_address) + icmp = ICMP(type="time-exceeded", code="ttl-zero-during-transit") + ip_inner = IP(dst=self.pg0.remote_ip4, + src=self.ipv4_map_address, ttl=1) + udp_inner = UDP(sport=self.ipv4_udp_or_tcp_map_port, + dport=self.ipv4_udp_or_tcp_internet_port) + payload = "H" * 10 + tx_pkt = eth / ip / icmp / ip_inner / udp_inner / payload + + self.pg_send(self.pg0, tx_pkt * 1) + + rx_pkts = self.pg1.get_capture(1) + rx_pkt = rx_pkts[0] + + self.v6_address_check(rx_pkt) + self.assertEqual(rx_pkt[IPv6].nh, IPv6(nh="ICMPv6").nh) + self.assertEqual(rx_pkt[ICMPv6TimeExceeded].type, + ICMPv6TimeExceeded().type) + self.assertEqual(rx_pkt[ICMPv6TimeExceeded].code, + ICMPv6TimeExceeded( + code="hop limit exceeded in transit").code) + self.assertEqual(rx_pkt[ICMPv6TimeExceeded].hlim, tx_pkt[IP][1].ttl) + self.assertTrue(rx_pkt.haslayer(IPerror6)) + self.assertTrue(rx_pkt.haslayer(UDPerror)) + self.assertEqual(rx_pkt[IPv6].src, rx_pkt[IPerror6].dst) + self.assertEqual(rx_pkt[IPv6].dst, rx_pkt[IPerror6].src) + self.assertEqual(rx_pkt[UDPerror].sport, self.ipv6_udp_or_tcp_map_port) + self.assertEqual(rx_pkt[UDPerror].dport, + self.ipv6_udp_or_tcp_internet_port) + # # Translation of ICMP Echo Request v6 -> v4 direction # Received packet should be translated into an IPv4 Echo Request. -- 2.16.6