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 <achernavin@netgate.com>
This commit is contained in:
Alexander Chernavin 2020-03-12 08:42:12 -04:00 committed by Ole Trøan
parent 1e844aa1ce
commit cd5a4a035c
2 changed files with 51 additions and 6 deletions

View File

@ -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)
{

View File

@ -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.