From 4d57ca6bf4be7dc69fe0a0d6b2911a22629a89d4 Mon Sep 17 00:00:00 2001 From: snrainw Date: Tue, 12 Dec 2023 19:18:08 +0800 Subject: [PATCH] Fix unable to send big UDP packets when SNAT rules are configured for nat46 In the IPv4->IPv6 direction, if SNAT rules are configured for nat46 (i.e. "iptables -A POSTROUTING -t nat -o clatd -j SNAT --to-source 182.0.0.111"), when the host sends a big udp packet (8000 bytes), the IP layer will fragment the packet. However, the fragments must be reassembled before doing NAT. The length of reassembled packet is less than nat46's mtu 16384, so it is not fragmented after NAT. Then nat46 converts it into an IPv6 packet, which causes the packet to be dropped by the network protocol stack and send an icmpv6 with "Fragmentation needed" to the source since the length of the packet is greater than the mtu of next hop and it is not sent locally. In order to send this packet, we should tell the network protocol stack that this is a locally sent IPv6 packet and fragment it if necessary. --- nat46/modules/nat46-core.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/nat46/modules/nat46-core.c b/nat46/modules/nat46-core.c index 8d7f257..aa79660 100644 --- a/nat46/modules/nat46-core.c +++ b/nat46/modules/nat46-core.c @@ -1979,6 +1979,17 @@ int nat46_ipv4_input(struct sk_buff *old_skb) { nat46debug(5, "about to send v6 packet, flags: %02x", IP6CB(new_skb)->flags); nat46_netdev_count_xmit(new_skb, old_skb->dev); + + /* + * Although the protocol stipulates that the intermediate routers prohibit + * fragmentation of IPv6 packets, we have done the translation from IPv4 + * to IPv6 here. The IPv6 packets are created by nat46, so the nat46 can be + * regarded as the sender. If fragmentation is needed, let the network + * protocol stack does it. + */ + if(0 == (ntohs(hdr4->frag_off) & 0x4000)) { + new_skb->local_df = 1; + } netif_rx(new_skb); done: