[PATCH 1/3] netfilter: ip6t_NPT: Align not mapped packets processing with RFC 6296 requirements

From: Nikolai Merinov

Date: Sun Nov 01 2026 - 15:39:03 EST


From: Andrey Kuznetsov <a.kuznetsov@xxxxxxxxxxxxxxxxxx>

The RFC 6296 section 3.2 have the following requirement:

> If the internal subnet number has no mapping, such as being 0xFFFF or
> simply not mapped, discard the datagram.

This requirement should be applied in two cases:

1. Both source and destination prefixes less than 48, and
addr->s6_addr16[3] equal to 0xFFFF.

2. When source prefix shorter than destination prefix, which means,
according to RFC 6296 section 3.7, that the shorter prefix should be
zero-extended to the length of the longer, all addresses from source
prefix that does not match zero-extended prefix is untranslatable.

Change code in manner to return false from ip6t_npt_map_pfx() function. The
callers interpret the false value as a flag to drop the packet.

Signed-off-by: Andrey Kuznetsov <a.kuznetsov@xxxxxxxxxxxxxxxxxx>
Co-developed-by: Nikolai Merinov <n.merinov@xxxxxxxxxxxxxxxxxx>
Signed-off-by: Nikolai Merinov <n.merinov@xxxxxxxxxxxxxxxxxx>
---
net/ipv6/netfilter/ip6t_NPT.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c
index 787c74aa85e3..6a939e1a9fbc 100644
--- a/net/ipv6/netfilter/ip6t_NPT.c
+++ b/net/ipv6/netfilter/ip6t_NPT.c
@@ -52,13 +52,18 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt,
mask = htonl((1 << (i - pfx_len + 32)) - 1);

idx = i / 32;
+ if ((addr->s6_addr32[idx] & ~mask) != npt->src_pfx.in6.s6_addr32[idx])
+ return false;
+
addr->s6_addr32[idx] &= mask;
addr->s6_addr32[idx] |= ~mask & npt->dst_pfx.in6.s6_addr32[idx];
}

- if (pfx_len <= 48)
+ if (pfx_len <= 48) {
idx = 3;
- else {
+ if ((__force __sum16)addr->s6_addr16[idx] == CSUM_MANGLED_0)
+ return false;
+ } else {
for (idx = 4; idx < ARRAY_SIZE(addr->s6_addr16); idx++) {
if ((__force __sum16)addr->s6_addr16[idx] !=
CSUM_MANGLED_0)
--
2.55.0