ip: translate fragmented icmp to fragmented icmp6

The first translated ICMPv6 packet of a fragmented ICMP message does
not have a IPv6 fragment header. All subsequent have.

With this commit, add a IPv6 fragment header to the first translated
ICMPv6 packet.

Type: fix

Change-Id: Id89409ce7273cbeed801e2e18a09d3e7c3c4e4bc
Signed-off-by: Alexander Chernavin <achernavin@netgate.com>
This commit is contained in:
Alexander Chernavin
2020-01-31 09:19:49 -05:00
committed by Ole Trøan
parent 0f96673683
commit 8af24b145c
2 changed files with 59 additions and 9 deletions

View File

@ -12,7 +12,8 @@ import scapy.compat
from scapy.layers.l2 import Ether from scapy.layers.l2 import Ether
from scapy.packet import Raw from scapy.packet import Raw
from scapy.layers.inet import IP, UDP, ICMP, TCP from scapy.layers.inet import IP, UDP, ICMP, TCP
from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded, IPv6ExtHdrFragment from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded, IPv6ExtHdrFragment, \
ICMPv6EchoRequest
class TestMAP(VppTestCase): class TestMAP(VppTestCase):
@ -597,7 +598,7 @@ class TestMAP(VppTestCase):
p6 = (p_ether6 / p_ip6 / payload) p6 = (p_ether6 / p_ip6 / payload)
self.send_and_assert_no_replies(self.pg1, p6*1) self.send_and_assert_no_replies(self.pg1, p6*1)
# Packet fragmentation # UDP packet fragmentation
payload_len = 1453 payload_len = 1453
payload = UDP(sport=40000, dport=4000) / self.payload(payload_len) payload = UDP(sport=40000, dport=4000) / self.payload(payload_len)
p4 = (p_ether / p_ip4 / payload) p4 = (p_ether / p_ip4 / payload)
@ -613,7 +614,7 @@ class TestMAP(VppTestCase):
self.validate_frag_payload_len(rx, UDP, payload_len) self.validate_frag_payload_len(rx, UDP, payload_len)
# Packet fragmentation send fragments # UDP packet fragmentation send fragments
payload = UDP(sport=40000, dport=4000) / self.payload(payload_len) payload = UDP(sport=40000, dport=4000) / self.payload(payload_len)
p4 = (p_ether / p_ip4 / payload) p4 = (p_ether / p_ip4 / payload)
frags = fragment_rfc791(p4, fragsize=1000) frags = fragment_rfc791(p4, fragsize=1000)
@ -627,10 +628,34 @@ class TestMAP(VppTestCase):
self.validate_frag_payload_len(rx, UDP, payload_len) self.validate_frag_payload_len(rx, UDP, payload_len)
# reass_pkt = reassemble(rx) # ICMP packet fragmentation
# p4_reply.ttl -= 1 payload = ICMP(id=6529) / self.payload(payload_len)
# p4_reply.id = 256 p4 = (p_ether / p_ip4 / payload)
# self.validate(reass_pkt, p4_reply) 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_frag(p, p_ip6_translated)
self.validate_frag_payload_len(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_frag(p, p_ip6_translated)
self.validate_frag_payload_len(rx, ICMPv6EchoRequest, payload_len)
# TCP MSS clamping # TCP MSS clamping
self.vapi.map_param_set_tcp(1300) self.vapi.map_param_set_tcp(1300)

View File

@ -226,8 +226,10 @@ icmp_to_icmp6 (vlib_buffer_t * p, ip4_to_ip6_set_fn_t fn, void *ctx,
icmp46_header_t *icmp; icmp46_header_t *icmp;
ip_csum_t csum; ip_csum_t csum;
ip6_frag_hdr_t *inner_frag; ip6_frag_hdr_t *inner_frag;
ip6_frag_hdr_t *outer_frag= NULL;
u32 inner_frag_id; u32 inner_frag_id;
u32 inner_frag_offset; u32 inner_frag_offset;
u32 outer_frag_id;
u8 inner_frag_more; u8 inner_frag_more;
u16 *inner_L4_checksum = 0; u16 *inner_L4_checksum = 0;
int rv; int rv;
@ -397,8 +399,20 @@ icmp_to_icmp6 (vlib_buffer_t * p, ip4_to_ip6_set_fn_t fn, void *ctx,
} }
else else
{ {
vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6)); if (PREDICT_FALSE (ip4->flags_and_fragment_offset &
ip6 = vlib_buffer_get_current (p); clib_host_to_net_u16 (IP4_HEADER_FLAG_MORE_FRAGMENTS)))
{
vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6) -
sizeof (*outer_frag));
ip6 = vlib_buffer_get_current (p);
outer_frag = (ip6_frag_hdr_t *) (ip6 + 1);
outer_frag_id = frag_id_4to6 (ip4->fragment_id);
}
else
{
vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6));
ip6 = vlib_buffer_get_current (p);
}
ip6->payload_length = ip6->payload_length =
clib_host_to_net_u16 (clib_net_to_host_u16 (ip4->length) - clib_host_to_net_u16 (clib_net_to_host_u16 (ip4->length) -
sizeof (*ip4)); sizeof (*ip4));
@ -414,6 +428,17 @@ icmp_to_icmp6 (vlib_buffer_t * p, ip4_to_ip6_set_fn_t fn, void *ctx,
if ((rv = fn (p, ip4, ip6, ctx)) != 0) if ((rv = fn (p, ip4, ip6, ctx)) != 0)
return rv; return rv;
if (PREDICT_FALSE (outer_frag != NULL))
{
outer_frag->next_hdr = ip6->protocol;
outer_frag->identification = outer_frag_id;
outer_frag->rsv = 0;
outer_frag->fragment_offset_and_more = ip6_frag_hdr_offset_and_more (0, 1);
ip6->protocol = IP_PROTOCOL_IPV6_FRAGMENTATION;
ip6->payload_length = u16_net_add (ip6->payload_length,
sizeof (*outer_frag));
}
//Truncate when ICMPv6 error message exceeds the minimal IPv6 MTU //Truncate when ICMPv6 error message exceeds the minimal IPv6 MTU
if (p->current_length > 1280 && icmp->type < 128) if (p->current_length > 1280 && icmp->type < 128)
{ {