From c192351e202b531a457835072888bb8a405c79ee Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 28 Aug 2025 08:33:59 -0700 Subject: [PATCH] [nat64] prevent IPv4 addr sharing when port translation is disabled (#11865) The logic for sharing an IPv4 address, intended for scenarios with a small address pool (CIDR prefix > /28), was incorrectly being applied even when port translation was disabled. When `OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE` is disabled, each mapping requires a unique IPv4 address. The previous implementation would incorrectly reuse the same address from the pool. This commit makes the address sharing logic conditional on the `OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE` configuration. When disabled, the translator now correctly allocates a unique IPv4 address for each mapping and returns it to the pool upon release. --- src/core/net/nat64_translator.cpp | 19 ++++++++++++++----- src/core/net/nat64_translator.hpp | 23 ++++++++++++++++++----- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/core/net/nat64_translator.cpp b/src/core/net/nat64_translator.cpp index 8580e36cd..25859f8b1 100644 --- a/src/core/net/nat64_translator.cpp +++ b/src/core/net/nat64_translator.cpp @@ -381,12 +381,17 @@ void Translator::Mapping::CopyTo(AddressMapping &aMapping, TimeMilli aNow) const void Translator::ReleaseMapping(Mapping &aMapping) { - if (mIp4Cidr.mLength <= kMaxCidrLenForValidAddrPool) +#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE + if (mIp4Cidr.mLength > kAddressMappingCidrLimit) { + // If `CONFIG_NAT64_PORT_TRANSLATION_ENABLE` is enabled // IPv4 addresses are allocated from the pool only when the // pool size is above a minimum value. Otherwise use just the - // first address from the list and we are not removing it - // from the array. + // first address from the pool. + } + else +#endif + { IgnoreError(mIp4AddressPool.PushBack(aMapping.mIp4Address)); } @@ -450,7 +455,9 @@ Translator::Mapping *Translator::AllocateMapping(const Ip6::Headers &aIp6Headers Mapping *mapping = nullptr; Ip4::Address ip4Addr; - // The NAT64 translator can work in 2 ways, either with a single +#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE + // When port translation (`NAT64_PORT_TRANSLATION`) is enabled + // the NAT64 translator can work in 2 ways, either with a single // IPv4 address or a larger pool of addresses. There is also the // corner case where the address pool is generated from a big // CIDR length and the number of available IPv4 addresses is not @@ -461,12 +468,13 @@ Translator::Mapping *Translator::AllocateMapping(const Ip6::Headers &aIp6Headers // larger pool is available each active mapping will use a // separate IPv4 address. - if (mIp4Cidr.mLength > kMaxCidrLenForValidAddrPool) + if (mIp4Cidr.mLength > kAddressMappingCidrLimit) { // TODO: add logic to cycle between available IPv4 addresses ip4Addr = *mIp4AddressPool.At(0); } else +#endif { if (mIp4AddressPool.IsEmpty()) { @@ -475,6 +483,7 @@ Translator::Mapping *Translator::AllocateMapping(const Ip6::Headers &aIp6Headers VerifyOrExit(ReleaseExpiredMappings() > 0); } + ip4Addr = *mIp4AddressPool.PopBack(); } diff --git a/src/core/net/nat64_translator.hpp b/src/core/net/nat64_translator.hpp index b7b99dbcf..dc0e717be 100644 --- a/src/core/net/nat64_translator.hpp +++ b/src/core/net/nat64_translator.hpp @@ -296,13 +296,26 @@ private: static constexpr uint32_t kIdleTimeout = OPENTHREAD_CONFIG_NAT64_IDLE_TIMEOUT_SECONDS * Time::kOneSecondInMsec; static constexpr uint32_t kIcmpTimeout = OPENTHREAD_CONFIG_NAT64_ICMP_IDLE_TIMEOUT_SECONDS * Time::kOneSecondInMsec; - static constexpr uint32_t kPoolSize = OPENTHREAD_CONFIG_NAT64_MAX_MAPPINGS; + static constexpr uint32_t kPoolSize = OPENTHREAD_CONFIG_NAT64_MAX_MAPPINGS; + +#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE + // Under `PORT_TRANSLATION_ENABLE`, the translator can operate in + // two modes: 1-to-1 address mapping where each IPv6 address gets + // a unique IPv4 address from a pool, or having the mappings + // share one (or a few) IPv4 addresses and are distinguished by + // the translated port numbers. + // + // This constant defines the maximum allowed CIDR prefix length + // for the IPv4 address pool to be considered large enough to use + // 1-to-1 address mapping. If the configured prefix length is + // greater than this value (e.g., /29, /30), the address pool is + // too small, and the translator will fall back to using port + // translation. + static constexpr uint8_t kAddressMappingCidrLimit = 28; + static constexpr uint16_t kMinTranslationPort = 49152; static constexpr uint16_t kMaxTranslationPort = 65535; - - // The maximum value the CIDR len can have in order to have a big - // enough pool to support a minimal number of devices - static constexpr uint8_t kMaxCidrLenForValidAddrPool = 28; +#endif static constexpr DropReason kReasonUnknown = OT_NAT64_DROP_REASON_UNKNOWN; static constexpr DropReason kReasonIllegalPacket = OT_NAT64_DROP_REASON_ILLEGAL_PACKET;