summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Chernavin <achernavin@netgate.com>2020-03-06 06:11:07 -0500
committerMatthew Smith <mgsmith@netgate.com>2020-03-24 14:28:34 +0000
commit46d0ff3945404f7c95e0e504f98f466e155ab753 (patch)
treea517e9ed68c3afe0d57db62e717ed6e5f32188c0
parent1839fe165c7ffb834775b8582fe0ee2321ff2ab6 (diff)
map: fix translation of icmp6 error messages
Translation of ICMPv6 error messages to ICMP error messages fails because the sender port is not set that leads to securtiy check failure. With this commit, during ICMPv6 error messages translation, get the sender port value from the inner packet. Type: fix Change-Id: I1ee295a3685fab4837172edfb629a699f49afbee Signed-off-by: Alexander Chernavin <achernavin@netgate.com>
-rw-r--r--src/plugins/map/test/test_map_br.py81
-rw-r--r--src/vnet/ip/ip6_to_ip4.h51
2 files changed, 131 insertions, 1 deletions
diff --git a/src/plugins/map/test/test_map_br.py b/src/plugins/map/test/test_map_br.py
index 631517e5d4e..3602ddd2e31 100644
--- a/src/plugins/map/test/test_map_br.py
+++ b/src/plugins/map/test/test_map_br.py
@@ -12,7 +12,7 @@ import scapy.compat
from scapy.layers.l2 import Ether
from scapy.packet import Raw
from scapy.layers.inet import IP, UDP, ICMP, TCP, IPerror, UDPerror
-from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded, IPv6ExtHdrFragment
+from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded, ICMPv6PacketTooBig
from scapy.layers.inet6 import ICMPv6EchoRequest, ICMPv6EchoReply, IPerror6
@@ -427,6 +427,85 @@ class TestMAPBR(VppTestCase):
self.assertEqual(rx_pkt[ICMP].id, self.ipv6_udp_or_tcp_map_port)
#
+ # Translation of ICMP Packet Too Big v6 -> v4 direction
+ # Received packet should be translated into an IPv4 Dest Unreachable.
+ #
+
+ def test_map_t_packet_too_big_ip6_to_ip4(self):
+ """ MAP-T packet too big IPv6 -> IPv4 """
+
+ eth = Ether(src=self.pg1.remote_mac,
+ dst=self.pg1.local_mac)
+ ip = IPv6(src=self.ipv6_cpe_address,
+ dst=self.ipv6_map_address)
+ icmp = ICMPv6PacketTooBig(mtu=1280)
+ ip_inner = IPv6(src=self.ipv6_map_address,
+ dst=self.ipv6_cpe_address)
+ udp_inner = UDP(sport=self.ipv6_udp_or_tcp_internet_port,
+ dport=self.ipv6_udp_or_tcp_map_port)
+ payload = "H" * 10
+ tx_pkt = eth / ip / icmp / ip_inner / udp_inner / payload
+
+ self.pg_send(self.pg1, tx_pkt * 1)
+
+ rx_pkts = self.pg0.get_capture(1)
+ rx_pkt = rx_pkts[0]
+
+ self.v4_address_check(rx_pkt)
+ self.assertEqual(rx_pkt[IP].proto, IP(proto="icmp").proto)
+ self.assertEqual(rx_pkt[ICMP].type, ICMP(type="dest-unreach").type)
+ self.assertEqual(rx_pkt[ICMP].code,
+ ICMP(code="fragmentation-needed").code)
+ self.assertEqual(rx_pkt[ICMP].nexthopmtu,
+ tx_pkt[ICMPv6PacketTooBig].mtu - 20)
+ self.assertTrue(rx_pkt.haslayer(IPerror))
+ self.assertTrue(rx_pkt.haslayer(UDPerror))
+ self.assertEqual(rx_pkt[IP].src, rx_pkt[IPerror].dst)
+ self.assertEqual(rx_pkt[IP].dst, rx_pkt[IPerror].src)
+ self.assertEqual(rx_pkt[UDPerror].sport,
+ self.ipv4_udp_or_tcp_internet_port)
+ self.assertEqual(rx_pkt[UDPerror].dport, self.ipv4_udp_or_tcp_map_port)
+
+ #
+ # Translation of ICMP Time Exceeded v6 -> v4 direction
+ # Received packet should be translated into an IPv4 Time Exceeded.
+ #
+
+ def test_map_t_time_exceeded_ip6_to_ip4(self):
+ """ MAP-T time exceeded IPv6 -> IPv4 """
+
+ eth = Ether(src=self.pg1.remote_mac,
+ dst=self.pg1.local_mac)
+ ip = IPv6(src=self.ipv6_cpe_address,
+ dst=self.ipv6_map_address)
+ icmp = ICMPv6TimeExceeded()
+ ip_inner = IPv6(src=self.ipv6_map_address,
+ dst=self.ipv6_cpe_address, hlim=1)
+ udp_inner = UDP(sport=self.ipv6_udp_or_tcp_internet_port,
+ dport=self.ipv6_udp_or_tcp_map_port)
+ payload = "H" * 10
+ tx_pkt = eth / ip / icmp / ip_inner / udp_inner / payload
+
+ self.pg_send(self.pg1, tx_pkt * 1)
+
+ rx_pkts = self.pg0.get_capture(1)
+ rx_pkt = rx_pkts[0]
+
+ self.v4_address_check(rx_pkt)
+ self.assertEqual(rx_pkt[IP].proto, IP(proto="icmp").proto)
+ self.assertEqual(rx_pkt[ICMP].type, ICMP(type="time-exceeded").type)
+ self.assertEqual(rx_pkt[ICMP].code,
+ ICMP(code="ttl-zero-during-transit").code)
+ self.assertEqual(rx_pkt[ICMP].ttl, tx_pkt[IPv6][1].hlim)
+ self.assertTrue(rx_pkt.haslayer(IPerror))
+ self.assertTrue(rx_pkt.haslayer(UDPerror))
+ self.assertEqual(rx_pkt[IP].src, rx_pkt[IPerror].dst)
+ self.assertEqual(rx_pkt[IP].dst, rx_pkt[IPerror].src)
+ self.assertEqual(rx_pkt[UDPerror].sport,
+ self.ipv4_udp_or_tcp_internet_port)
+ self.assertEqual(rx_pkt[UDPerror].dport, self.ipv4_udp_or_tcp_map_port)
+
+ #
# Spoofed IPv4 Source Address v6 -> v4 direction
# Send a packet with a wrong IPv4 address embedded in bits 72-103.
# The BR should either drop the packet, or rewrite the spoofed
diff --git a/src/vnet/ip/ip6_to_ip4.h b/src/vnet/ip/ip6_to_ip4.h
index 17a11e6df0a..6a533e3b54e 100644
--- a/src/vnet/ip/ip6_to_ip4.h
+++ b/src/vnet/ip/ip6_to_ip4.h
@@ -170,6 +170,57 @@ ip6_get_port (vlib_main_t * vm, vlib_buffer_t * b, ip6_header_t * ip6,
if (dst_port)
*dst_port = ((u16 *) (icmp))[2];
}
+ else if (clib_net_to_host_u16 (ip6->payload_length) >= 64)
+ {
+ u16 ip6_pay_len;
+ ip6_header_t *inner_ip6;
+ u8 inner_l4_protocol;
+ u16 inner_l4_offset;
+ u16 inner_frag_offset;
+ u8 *inner_l4;
+
+ ip6_pay_len = clib_net_to_host_u16 (ip6->payload_length);
+ inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8);
+
+ if (ip6_parse (vm, b, inner_ip6, ip6_pay_len - 8,
+ &inner_l4_protocol, &inner_l4_offset,
+ &inner_frag_offset))
+ return 0;
+
+ if (inner_frag_offset &&
+ ip6_frag_hdr_offset (((ip6_frag_hdr_t *)
+ u8_ptr_add (inner_ip6,
+ inner_frag_offset))))
+ return 0;
+
+ inner_l4 = u8_ptr_add (inner_ip6, inner_l4_offset);
+ if (inner_l4_protocol == IP_PROTOCOL_TCP ||
+ inner_l4_protocol == IP_PROTOCOL_UDP)
+ {
+ if (src_port)
+ *src_port = ((udp_header_t *) (inner_l4))->dst_port;
+ if (dst_port)
+ *dst_port = ((udp_header_t *) (inner_l4))->src_port;
+ }
+ else if (inner_l4_protocol == IP_PROTOCOL_ICMP6)
+ {
+ icmp46_header_t *inner_icmp = (icmp46_header_t *) (inner_l4);
+ if (inner_icmp->type == ICMP6_echo_request)
+ {
+ if (src_port)
+ *src_port = ((u16 *) (inner_icmp))[2];
+ if (dst_port)
+ *dst_port = ((u16 *) (inner_icmp))[2];
+ }
+ else if (inner_icmp->type == ICMP6_echo_reply)
+ {
+ if (src_port)
+ *src_port = ((u16 *) (inner_icmp))[2];
+ if (dst_port)
+ *dst_port = ((u16 *) (inner_icmp))[2];
+ }
+ }
+ }
}
return 1;
}