[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.
This commit is contained in:
Abtin Keshavarzian
2025-08-28 08:33:59 -07:00
committed by GitHub
parent 54195e0ecf
commit c192351e20
2 changed files with 32 additions and 10 deletions
+14 -5
View File
@@ -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();
}
+18 -5
View File
@@ -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;