From 6dfb82dc4a7264b440fb4680f395ceeb8a853761 Mon Sep 17 00:00:00 2001 From: shichunma Date: Sat, 1 Aug 2026 21:54:32 +0800 Subject: [PATCH] net/nat: Reassemble IPv6 fragments before NAT66 NAT66 needs transport headers to create or match address and port mappings. Consume IPv6 fragments through local reassembly before NAT66 processing so forwarded fragmented traffic is not translated fragment-by-fragment without L4 context. Also dispatch inbound NAT66 using the parsed IPv6 next-header value, matching the outbound path and allowing packets with extension headers before the transport header to be translated. Signed-off-by: shichunma --- net/devif/ipv6_input.c | 51 +++++++++++++++++++++++++++++++----------- net/nat/ipv6_nat.c | 2 +- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/net/devif/ipv6_input.c b/net/devif/ipv6_input.c index dc1c04360de..7236d320a10 100644 --- a/net/devif/ipv6_input.c +++ b/net/devif/ipv6_input.c @@ -151,6 +151,36 @@ static bool check_destipaddr(FAR struct net_driver_s *dev, return false; } +#if defined(CONFIG_NET_IPFRAG) || defined(CONFIG_NET_NAT66) +/**************************************************************************** + * Name: ipv6_fragin_or_drop + * + * Description: + * Reassemble an incoming IPv6 fragment for NAT or local processing or drop + * it if fragment reassembly is not available. + * + ****************************************************************************/ + +static int ipv6_fragin_or_drop(FAR struct net_driver_s *dev) +{ +#ifdef CONFIG_NET_IPFRAG + if (ipv6_fragin(dev) == OK) + { + return OK; + } +#endif + +#ifdef CONFIG_NET_STATISTICS + g_netstats.ipv6.drop++; + g_netstats.ipv6.fragerr++; +#endif + nwarn("WARNING: IPv6 fragment dropped\n"); + + dev->d_len = 0; + return OK; +} +#endif + /**************************************************************************** * Name: ipv6_in * @@ -195,7 +225,7 @@ static int ipv6_in(FAR struct net_driver_s *dev) #ifdef CONFIG_NET_IPFORWARD int ret; #endif -#ifdef CONFIG_NET_IPFRAG +#if defined(CONFIG_NET_IPFRAG) || defined(CONFIG_NET_NAT66) bool isfrag = false; #endif @@ -287,7 +317,7 @@ static int ipv6_in(FAR struct net_driver_s *dev) if (nxthdr == NEXT_FRAGMENT_EH) { extlen = EXTHDR_FRAG_LEN; -#ifdef CONFIG_NET_IPFRAG +#if defined(CONFIG_NET_IPFRAG) || defined(CONFIG_NET_NAT66) isfrag = true; #endif } @@ -302,6 +332,11 @@ static int ipv6_in(FAR struct net_driver_s *dev) } #ifdef CONFIG_NET_NAT66 + if (isfrag) + { + return ipv6_fragin_or_drop(dev); + } + /* Try NAT inbound, rule matching will be performed in NAT module. */ ipv6_nat_inbound(dev, ipv6); @@ -410,17 +445,7 @@ static int ipv6_in(FAR struct net_driver_s *dev) #ifdef CONFIG_NET_IPFRAG if (isfrag) { - if (ipv6_fragin(dev) == OK) - { - return OK; - } - else - { -#ifdef CONFIG_NET_STATISTICS - g_netstats.ipv6.fragerr++; -#endif - goto drop; - } + return ipv6_fragin_or_drop(dev); } #endif diff --git a/net/nat/ipv6_nat.c b/net/nat/ipv6_nat.c index 1c0f16ec955..4a40d2cc4be 100644 --- a/net/nat/ipv6_nat.c +++ b/net/nat/ipv6_nat.c @@ -540,7 +540,7 @@ ipv6_nat_inbound_internal(FAR struct ipv6_hdr_s *ipv6, uint8_t proto; FAR void *l4hdr = net_ipv6_payload(ipv6, &proto); - switch (ipv6->proto) + switch (proto) { #ifdef CONFIG_NET_TCP case IP_PROTO_TCP: