| From 5153f2fc5039e5ee4be6e07389639a457d4f2a8b Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 22 Jul 2021 20:01:28 +0300 |
| Subject: net: Set true network header for ECN decapsulation |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Gilad Naaman <gnaaman@drivenets.com> |
| |
| [ Upstream commit 227adfb2b1dfbc53dfc53b9dd7a93a6298ff7c56 ] |
| |
| In cases where the header straight after the tunnel header was |
| another ethernet header (TEB), instead of the network header, |
| the ECN decapsulation code would treat the ethernet header as if |
| it was an IP header, resulting in mishandling and possible |
| wrong drops or corruption of the IP header. |
| |
| In this case, ECT(1) is sent, so IP_ECN_decapsulate tries to copy it to the |
| inner IPv4 header, and correct its checksum. |
| |
| The offset of the ECT bits in an IPv4 header corresponds to the |
| lower 2 bits of the second octet of the destination MAC address |
| in the ethernet header. |
| The IPv4 checksum corresponds to end of the source address. |
| |
| In order to reproduce: |
| |
| $ ip netns add A |
| $ ip netns add B |
| $ ip -n A link add _v0 type veth peer name _v1 netns B |
| $ ip -n A link set _v0 up |
| $ ip -n A addr add dev _v0 10.254.3.1/24 |
| $ ip -n A route add default dev _v0 scope global |
| $ ip -n B link set _v1 up |
| $ ip -n B addr add dev _v1 10.254.1.6/24 |
| $ ip -n B route add default dev _v1 scope global |
| $ ip -n B link add gre1 type gretap local 10.254.1.6 remote 10.254.3.1 key 0x49000000 |
| $ ip -n B link set gre1 up |
| |
| # Now send an IPv4/GRE/Eth/IPv4 frame where the outer header has ECT(1), |
| # and the inner header has no ECT bits set: |
| |
| $ cat send_pkt.py |
| #!/usr/bin/env python3 |
| from scapy.all import * |
| |
| pkt = IP(b'E\x01\x00\xa7\x00\x00\x00\x00@/`%\n\xfe\x03\x01\n\xfe\x01\x06 \x00eXI\x00' |
| b'\x00\x00\x18\xbe\x92\xa0\xee&\x18\xb0\x92\xa0l&\x08\x00E\x00\x00}\x8b\x85' |
| b'@\x00\x01\x01\xe4\xf2\x82\x82\x82\x01\x82\x82\x82\x02\x08\x00d\x11\xa6\xeb' |
| b'3\x1e\x1e\\xf3\\xf7`\x00\x00\x00\x00ZN\x00\x00\x00\x00\x00\x00\x10\x11\x12' |
| b'\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234' |
| b'56789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ') |
| |
| send(pkt) |
| $ sudo ip netns exec B tcpdump -neqlllvi gre1 icmp & ; sleep 1 |
| $ sudo ip netns exec A python3 send_pkt.py |
| |
| In the original packet, the source/destinatio MAC addresses are |
| dst=18:be:92:a0:ee:26 src=18:b0:92:a0:6c:26 |
| |
| In the received packet, they are |
| dst=18:bd:92:a0:ee:26 src=18:b0:92:a0:6c:27 |
| |
| Thanks to Lahav Schlesinger <lschlesinger@drivenets.com> and Isaac Garzon <isaac@speed.io> |
| for helping me pinpoint the origin. |
| |
| Fixes: b723748750ec ("tunnel: Propagate ECT(1) when decapsulating as recommended by RFC6040") |
| Cc: David S. Miller <davem@davemloft.net> |
| Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org> |
| Cc: David Ahern <dsahern@kernel.org> |
| Cc: Jakub Kicinski <kuba@kernel.org> |
| Cc: Toke Høiland-Jørgensen <toke@redhat.com> |
| Signed-off-by: Gilad Naaman <gnaaman@drivenets.com> |
| Acked-by: Toke Høiland-Jørgensen <toke@redhat.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/ipv4/ip_tunnel.c | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c |
| index 0dca00745ac3..be75b409445c 100644 |
| --- a/net/ipv4/ip_tunnel.c |
| +++ b/net/ipv4/ip_tunnel.c |
| @@ -390,7 +390,7 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, |
| tunnel->i_seqno = ntohl(tpi->seq) + 1; |
| } |
| |
| - skb_reset_network_header(skb); |
| + skb_set_network_header(skb, (tunnel->dev->type == ARPHRD_ETHER) ? ETH_HLEN : 0); |
| |
| err = IP_ECN_decapsulate(iph, skb); |
| if (unlikely(err)) { |
| -- |
| 2.30.2 |
| |