Patch "xfrm: fix tunnel model fragmentation behavior" has been added to the 5.16-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    xfrm: fix tunnel model fragmentation behavior

to the 5.16-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     xfrm-fix-tunnel-model-fragmentation-behavior.patch
and it can be found in the queue-5.16 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit c6918f523832f11f5e10d5fa271f3672bab989b8
Author: Lina Wang <lina.wang@xxxxxxxxxxxx>
Date:   Sat Feb 26 15:48:01 2022 +0800

    xfrm: fix tunnel model fragmentation behavior
    
    [ Upstream commit 4ff2980b6bd2aa6b4ded3ce3b7c0ccfab29980af ]
    
    in tunnel mode, if outer interface(ipv4) is less, it is easily to let
    inner IPV6 mtu be less than 1280. If so, a Packet Too Big ICMPV6 message
    is received. When send again, packets are fragmentized with 1280, they
    are still rejected with ICMPV6(Packet Too Big) by xfrmi_xmit2().
    
    According to RFC4213 Section3.2.2:
    if (IPv4 path MTU - 20) is less than 1280
            if packet is larger than 1280 bytes
                    Send ICMPv6 "packet too big" with MTU=1280
                    Drop packet
            else
                    Encapsulate but do not set the Don't Fragment
                    flag in the IPv4 header.  The resulting IPv4
                    packet might be fragmented by the IPv4 layer
                    on the encapsulator or by some router along
                    the IPv4 path.
            endif
    else
            if packet is larger than (IPv4 path MTU - 20)
                    Send ICMPv6 "packet too big" with
                    MTU = (IPv4 path MTU - 20).
                    Drop packet.
            else
                    Encapsulate and set the Don't Fragment flag
                    in the IPv4 header.
            endif
    endif
    Packets should be fragmentized with ipv4 outer interface, so change it.
    
    After it is fragemtized with ipv4, there will be double fragmenation.
    No.48 & No.51 are ipv6 fragment packets, No.48 is double fragmentized,
    then tunneled with IPv4(No.49& No.50), which obey spec. And received peer
    cannot decrypt it rightly.
    
    48              2002::10        2002::11 1296(length) IPv6 fragment (off=0 more=y ident=0xa20da5bc nxt=50)
    49   0x0000 (0) 2002::10        2002::11 1304         IPv6 fragment (off=0 more=y ident=0x7448042c nxt=44)
    50   0x0000 (0) 2002::10        2002::11 200          ESP (SPI=0x00035000)
    51              2002::10        2002::11 180          Echo (ping) request
    52   0x56dc     2002::10        2002::11 248          IPv6 fragment (off=1232 more=n ident=0xa20da5bc nxt=50)
    
    xfrm6_noneed_fragment has fixed above issues. Finally, it acted like below:
    1   0x6206 192.168.1.138   192.168.1.1 1316 Fragmented IP protocol (proto=Encap Security Payload 50, off=0, ID=6206) [Reassembled in #2]
    2   0x6206 2002::10        2002::11    88   IPv6 fragment (off=0 more=y ident=0x1f440778 nxt=50)
    3   0x0000 2002::10        2002::11    248  ICMPv6    Echo (ping) request
    
    Signed-off-by: Lina Wang <lina.wang@xxxxxxxxxxxx>
    Signed-off-by: Steffen Klassert <steffen.klassert@xxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index d0d280077721..ad07904642ca 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -45,6 +45,19 @@ static int __xfrm6_output_finish(struct net *net, struct sock *sk, struct sk_buf
 	return xfrm_output(sk, skb);
 }
 
+static int xfrm6_noneed_fragment(struct sk_buff *skb)
+{
+	struct frag_hdr *fh;
+	u8 prevhdr = ipv6_hdr(skb)->nexthdr;
+
+	if (prevhdr != NEXTHDR_FRAGMENT)
+		return 0;
+	fh = (struct frag_hdr *)(skb->data + sizeof(struct ipv6hdr));
+	if (fh->nexthdr == NEXTHDR_ESP || fh->nexthdr == NEXTHDR_AUTH)
+		return 1;
+	return 0;
+}
+
 static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb_dst(skb);
@@ -73,6 +86,9 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 		xfrm6_local_rxpmtu(skb, mtu);
 		kfree_skb(skb);
 		return -EMSGSIZE;
+	} else if (toobig && xfrm6_noneed_fragment(skb)) {
+		skb->ignore_df = 1;
+		goto skip_frag;
 	} else if (!skb->ignore_df && toobig && skb->sk) {
 		xfrm_local_error(skb, mtu);
 		kfree_skb(skb);
diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c
index 4e3c62d1ad9e..1e8b26eecb3f 100644
--- a/net/xfrm/xfrm_interface.c
+++ b/net/xfrm/xfrm_interface.c
@@ -304,7 +304,10 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
 			if (mtu < IPV6_MIN_MTU)
 				mtu = IPV6_MIN_MTU;
 
-			icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+			if (skb->len > 1280)
+				icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+			else
+				goto xmit;
 		} else {
 			if (!(ip_hdr(skb)->frag_off & htons(IP_DF)))
 				goto xmit;



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux