/* * Copyright (c) 2025, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "core/net/ip4_types.hpp" #include "core/net/nat64_translator.hpp" #include "platform/nexus_core.hpp" #include "platform/nexus_node.hpp" namespace ot { namespace Nexus { static bool sNotifierCallbackInvoked = false; static otChangedFlags sNotifierEvents = 0; void HandleNotifierEvent(otChangedFlags aFlags, void *aContext) { VerifyOrQuit(aContext == nullptr); sNotifierCallbackInvoked = true; sNotifierEvents = aFlags; } void TestNat64StateChanges(void) { Core nexus; Node &node = nexus.CreateNode(); Ip6::Prefix prefix, testPrefix; Ip4::Cidr cidr, testCidr; Nat64::Translator::AddressMappingIterator iterator; Nat64::Translator::AddressMapping mapping; Log("------------------------------------------------------------------------------------------------------"); Log("TestNat64StateChanges"); nexus.AdvanceTime(0); node.Form(); nexus.AdvanceTime(50 * Time::kOneSecondInMsec); VerifyOrQuit(node.Get().IsLeader()); SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelInfo)); SuccessOrQuit(node.Get().RegisterCallback(HandleNotifierEvent, nullptr)); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check NAT64 Translator's initial state"); VerifyOrQuit(node.Get().GetState() == Nat64::kStateDisabled); VerifyOrQuit(node.Get().GetIp4Cidr(cidr) == kErrorNotFound); VerifyOrQuit(node.Get().GetNat64Prefix(prefix) == kErrorNotFound); iterator.Init(node.GetInstance()); VerifyOrQuit(iterator.GetNext(mapping) == kErrorNotFound); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Enable NAT64"); node.Get().SetEnabled(true); VerifyOrQuit(node.Get().GetState() == Nat64::kStateNotRunning); VerifyOrQuit(node.Get().GetIp4Cidr(cidr) == kErrorNotFound); VerifyOrQuit(node.Get().GetNat64Prefix(prefix) == kErrorNotFound); iterator.Init(node.GetInstance()); VerifyOrQuit(iterator.GetNext(mapping) == kErrorNotFound); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Set an invalid CIDR"); testCidr.Clear(); VerifyOrQuit(node.Get().SetIp4Cidr(testCidr) == kErrorInvalidArgs); VerifyOrQuit(node.Get().GetState() == Nat64::kStateNotRunning); VerifyOrQuit(node.Get().GetIp4Cidr(cidr) == kErrorNotFound); VerifyOrQuit(node.Get().GetNat64Prefix(prefix) == kErrorNotFound); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Set a valid CIDR"); SuccessOrQuit(testCidr.FromString("192.168.100.0/8")); SuccessOrQuit(node.Get().SetIp4Cidr(testCidr)); VerifyOrQuit(node.Get().GetState() == Nat64::kStateNotRunning); VerifyOrQuit(node.Get().GetNat64Prefix(prefix) == kErrorNotFound); SuccessOrQuit(node.Get().GetIp4Cidr(cidr)); VerifyOrQuit(cidr == testCidr); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Set a IPv6 NAT64 prefix"); SuccessOrQuit(testPrefix.FromString("fd01::/96")); node.Get().SetNat64Prefix(testPrefix); SuccessOrQuit(node.Get().GetNat64Prefix(prefix)); VerifyOrQuit(prefix == testPrefix); SuccessOrQuit(node.Get().GetIp4Cidr(cidr)); VerifyOrQuit(cidr == testCidr); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check that NAT64 is now active"); nexus.AdvanceTime(1); VerifyOrQuit(node.Get().GetState() == Nat64::kStateActive); VerifyOrQuit(sNotifierCallbackInvoked); VerifyOrQuit(sNotifierEvents & kEventNat64TranslatorStateChanged); SuccessOrQuit(node.Get().GetNat64Prefix(prefix)); VerifyOrQuit(prefix == testPrefix); SuccessOrQuit(node.Get().GetIp4Cidr(cidr)); VerifyOrQuit(cidr == testCidr); iterator.Init(node.GetInstance()); VerifyOrQuit(iterator.GetNext(mapping) == kErrorNotFound); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Disable and re-enable NAT64"); nexus.AdvanceTime(1000); VerifyOrQuit(node.Get().GetState() == Nat64::kStateActive); sNotifierCallbackInvoked = false; node.Get().SetEnabled(false); VerifyOrQuit(node.Get().GetState() == Nat64::kStateDisabled); SuccessOrQuit(node.Get().GetNat64Prefix(prefix)); VerifyOrQuit(prefix == testPrefix); SuccessOrQuit(node.Get().GetIp4Cidr(cidr)); VerifyOrQuit(cidr == testCidr); nexus.AdvanceTime(1); VerifyOrQuit(sNotifierCallbackInvoked); VerifyOrQuit(sNotifierEvents & kEventNat64TranslatorStateChanged); // Re-enable sNotifierCallbackInvoked = false; node.Get().SetEnabled(true); nexus.AdvanceTime(1); VerifyOrQuit(node.Get().GetState() == Nat64::kStateActive); VerifyOrQuit(sNotifierCallbackInvoked); VerifyOrQuit(sNotifierEvents & kEventNat64TranslatorStateChanged); SuccessOrQuit(node.Get().GetNat64Prefix(prefix)); VerifyOrQuit(prefix == testPrefix); SuccessOrQuit(node.Get().GetIp4Cidr(cidr)); VerifyOrQuit(cidr == testCidr); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Set the NAT64 prefix to the same value"); nexus.AdvanceTime(1000); node.Get().SetNat64Prefix(testPrefix); VerifyOrQuit(node.Get().GetState() == Nat64::kStateActive); SuccessOrQuit(node.Get().GetNat64Prefix(prefix)); VerifyOrQuit(prefix == testPrefix); SuccessOrQuit(node.Get().GetIp4Cidr(cidr)); VerifyOrQuit(cidr == testCidr); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Clear NAT64 prefix and ensure NAT64 is stopped"); nexus.AdvanceTime(1000); sNotifierCallbackInvoked = false; node.Get().ClearNat64Prefix(); nexus.AdvanceTime(1); VerifyOrQuit(node.Get().GetState() == Nat64::kStateNotRunning); VerifyOrQuit(node.Get().GetNat64Prefix(prefix) == kErrorNotFound); SuccessOrQuit(node.Get().GetIp4Cidr(cidr)); VerifyOrQuit(cidr == testCidr); VerifyOrQuit(sNotifierCallbackInvoked); VerifyOrQuit(sNotifierEvents & kEventNat64TranslatorStateChanged); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Change NAT64 prefix and ensure NAT64 is again active"); sNotifierCallbackInvoked = false; SuccessOrQuit(testPrefix.FromString("fd02::/96")); node.Get().SetNat64Prefix(testPrefix); nexus.AdvanceTime(1); VerifyOrQuit(node.Get().GetState() == Nat64::kStateActive); SuccessOrQuit(node.Get().GetNat64Prefix(prefix)); VerifyOrQuit(prefix == testPrefix); SuccessOrQuit(node.Get().GetIp4Cidr(cidr)); VerifyOrQuit(cidr == testCidr); VerifyOrQuit(sNotifierCallbackInvoked); VerifyOrQuit(sNotifierEvents & kEventNat64TranslatorStateChanged); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Clear the configured CIDR and ensure NAT64 is stopped"); nexus.AdvanceTime(1000); sNotifierCallbackInvoked = false; node.Get().ClearIp4Cidr(); nexus.AdvanceTime(1); VerifyOrQuit(node.Get().GetState() == Nat64::kStateNotRunning); SuccessOrQuit(node.Get().GetNat64Prefix(prefix)); VerifyOrQuit(prefix == testPrefix); VerifyOrQuit(node.Get().GetIp4Cidr(cidr) == kErrorNotFound); VerifyOrQuit(sNotifierCallbackInvoked); VerifyOrQuit(sNotifierEvents & kEventNat64TranslatorStateChanged); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Set the CIDR again and ensure NAT64 becomes active"); sNotifierCallbackInvoked = false; SuccessOrQuit(testCidr.FromString("192.168.200.1/32")); SuccessOrQuit(node.Get().SetIp4Cidr(testCidr)); nexus.AdvanceTime(1); VerifyOrQuit(node.Get().GetState() == Nat64::kStateActive); SuccessOrQuit(node.Get().GetNat64Prefix(prefix)); VerifyOrQuit(prefix == testPrefix); SuccessOrQuit(node.Get().GetIp4Cidr(cidr)); VerifyOrQuit(cidr == testCidr); VerifyOrQuit(sNotifierCallbackInvoked); VerifyOrQuit(sNotifierEvents & kEventNat64TranslatorStateChanged); Log("End of TestNat64StateChanges"); } Message *PrepareUdpMessage(Node &aNode, const Ip6::Address &aSrcIp6Address, const Ip4::Address &aDstIp4Address, uint16_t aSrcPort = 1234, uint16_t aDstPort = 1235, uint16_t aPayloadLen = 10) { Message *message = nullptr; Ip6::Prefix nat64Prefix; Ip6::Header ip6Header; Ip6::UdpHeader udpHeader; message = aNode.Get().Allocate(Message::kTypeIp6); VerifyOrQuit(message != nullptr); ip6Header.Clear(); ip6Header.InitVersionTrafficClassFlow(); ip6Header.SetSource(aSrcIp6Address); SuccessOrQuit(aNode.Get().GetNat64Prefix(nat64Prefix)); ip6Header.GetDestination().SynthesizeFromIp4Address(nat64Prefix, aDstIp4Address); ip6Header.SetNextHeader(Ip6::kProtoUdp); ip6Header.SetPayloadLength(sizeof(Ip6::UdpHeader) + aPayloadLen); SuccessOrQuit(message->Append(ip6Header)); udpHeader.Clear(); udpHeader.SetSourcePort(aSrcPort); udpHeader.SetDestinationPort(aDstPort); udpHeader.SetLength(aPayloadLen); SuccessOrQuit(message->Append(udpHeader)); for (uint16_t i = 0; i < aPayloadLen; i++) { SuccessOrQuit(message->Append(static_cast(i & 0xff))); } return message; } Message *PrepareTcpMessage(Node &aNode, const Ip6::Address &aSrcIp6Address, const Ip4::Address &aDstIp4Address, uint16_t aSrcPort = 1234, uint16_t aDstPort = 1235, uint16_t aPayloadLen = 10) { Message *message = nullptr; Ip6::Prefix nat64Prefix; Ip6::Header ip6Header; Ip6::TcpHeader tcpHeader; message = aNode.Get().Allocate(Message::kTypeIp6); VerifyOrQuit(message != nullptr); ip6Header.Clear(); ip6Header.InitVersionTrafficClassFlow(); ip6Header.SetSource(aSrcIp6Address); SuccessOrQuit(aNode.Get().GetNat64Prefix(nat64Prefix)); ip6Header.GetDestination().SynthesizeFromIp4Address(nat64Prefix, aDstIp4Address); ip6Header.SetNextHeader(Ip6::kProtoTcp); ip6Header.SetPayloadLength(sizeof(Ip6::TcpHeader) + aPayloadLen); SuccessOrQuit(message->Append(ip6Header)); tcpHeader.Clear(); tcpHeader.SetSourcePort(aSrcPort); tcpHeader.SetDestinationPort(aDstPort); SuccessOrQuit(message->Append(tcpHeader)); for (uint16_t i = 0; i < aPayloadLen; i++) { SuccessOrQuit(message->Append(static_cast(i & 0xff))); } return message; } Message *PrepareIcmp6Message(Node &aNode, const Ip6::Address &aSrcIp6Address, const Ip4::Address &aDstIp4Address, uint16_t aPayloadLen = 10) { Message *message = nullptr; Ip6::Prefix nat64Prefix; Ip6::Header ip6Header; Ip6::Icmp6Header icmpHeader; message = aNode.Get().Allocate(Message::kTypeIp6); VerifyOrQuit(message != nullptr); ip6Header.Clear(); ip6Header.InitVersionTrafficClassFlow(); ip6Header.SetSource(aSrcIp6Address); SuccessOrQuit(aNode.Get().GetNat64Prefix(nat64Prefix)); ip6Header.GetDestination().SynthesizeFromIp4Address(nat64Prefix, aDstIp4Address); ip6Header.SetNextHeader(Ip6::kProtoIcmp6); ip6Header.SetPayloadLength(sizeof(Ip6::Icmp6Header) + aPayloadLen); SuccessOrQuit(message->Append(ip6Header)); icmpHeader.Clear(); icmpHeader.SetType(Ip6::Icmp6Header::kTypeEchoRequest); SuccessOrQuit(message->Append(icmpHeader)); for (uint16_t i = 0; i < aPayloadLen; i++) { SuccessOrQuit(message->Append(static_cast(i & 0xff))); } message->SetOffset(sizeof(Ip6::Header)); Checksum::UpdateMessageChecksum(*message, ip6Header.GetSource(), ip6Header.GetDestination(), Ip6::kProtoIcmp6); return message; } void LogAddressMapping(const Nat64::Translator::AddressMapping &aMapping) { Log("Mapping: %s -> %s, remaining-time:%lu", AsCoreType(&aMapping.mIp6).ToString().AsCString(), AsCoreType(&aMapping.mIp4).ToString().AsCString(), ToUlong(aMapping.mRemainingTimeMs)); } void TestNat64Mapping(void) { static constexpr uint32_t kExpireTimeout = 2 * 610 * Time::kOneSecondInMsec; static constexpr uint16_t kSrcPort = 55387; static constexpr uint16_t kDstPort = 55388; static constexpr uint16_t kPayloadLength = 32; Core nexus; Node &node = nexus.CreateNode(); Ip6::Prefix prefix; Ip4::Cidr cidr; Nat64::Translator::AddressMappingIterator iterator; Nat64::Translator::AddressMapping mapping; OwnedPtr message; Ip6::Address ip6Addr; Ip6::Address ip6Addr2; Ip4::Address ip4Addr; Ip4::Headers ip4Headers; uint16_t count; Log("------------------------------------------------------------------------------------------------------"); Log("TestNat64Mapping"); nexus.AdvanceTime(0); node.Form(); nexus.AdvanceTime(50 * Time::kOneSecondInMsec); VerifyOrQuit(node.Get().IsLeader()); SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelInfo)); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Enable NAT64 translator"); SuccessOrQuit(prefix.FromString("fd01::/96")); SuccessOrQuit(cidr.FromString("192.168.100.0/24")); node.Get().SetNat64Prefix(prefix); SuccessOrQuit(node.Get().SetIp4Cidr(cidr)); node.Get().SetEnabled(true); VerifyOrQuit(node.Get().GetState() == Nat64::kStateActive); iterator.Init(node.GetInstance()); VerifyOrQuit(iterator.GetNext(mapping) == kErrorNotFound); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Translate an IPv6 message"); SuccessOrQuit(ip6Addr.FromString("fd02::1")); SuccessOrQuit(ip4Addr.FromString("200.100.1.1")); message.Reset(PrepareUdpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); SuccessOrQuit(ip4Headers.ParseFrom(*message)); VerifyOrQuit(ip4Headers.GetDestinationAddress() == ip4Addr); VerifyOrQuit(ip4Headers.IsUdp()); VerifyOrQuit(ip4Headers.GetSourcePort() == kSrcPort); VerifyOrQuit(ip4Headers.GetDestinationPort() == kDstPort); VerifyOrQuit(ip4Headers.GetUdpHeader().GetLength() == kPayloadLength); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check the created Address Mapping"); iterator.Init(node.GetInstance()); SuccessOrQuit(iterator.GetNext(mapping)); LogAddressMapping(mapping); VerifyOrQuit(AsCoreType(&mapping.mIp6) == ip6Addr); VerifyOrQuit(AsCoreType(&mapping.mIp4) == ip4Headers.GetSourceAddress()); VerifyOrQuit(mapping.mRemainingTimeMs > 0); VerifyOrQuit(iterator.GetNext(mapping) == kErrorNotFound); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Translate another IPv6 message from the same IPv6 sender to a new IPv4 dest"); SuccessOrQuit(ip4Addr.FromString("200.100.1.2")); message.Reset(PrepareUdpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength * 2)); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); SuccessOrQuit(ip4Headers.ParseFrom(*message)); VerifyOrQuit(ip4Headers.GetDestinationAddress() == ip4Addr); VerifyOrQuit(ip4Headers.IsUdp()); VerifyOrQuit(ip4Headers.GetSourcePort() == kSrcPort); VerifyOrQuit(ip4Headers.GetDestinationPort() == kDstPort); VerifyOrQuit(ip4Headers.GetUdpHeader().GetLength() == kPayloadLength * 2); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Ensure the previous Address Mapping is reused"); iterator.Init(node.GetInstance()); SuccessOrQuit(iterator.GetNext(mapping)); LogAddressMapping(mapping); VerifyOrQuit(AsCoreType(&mapping.mIp6) == ip6Addr); VerifyOrQuit(AsCoreType(&mapping.mIp4) == ip4Headers.GetSourceAddress()); VerifyOrQuit(mapping.mRemainingTimeMs > 0); VerifyOrQuit(iterator.GetNext(mapping) == kErrorNotFound); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Translate a new IPv6 message from a new IPv6 address"); nexus.AdvanceTime(30 * 1000); SuccessOrQuit(ip6Addr2.FromString("fd02::2")); message.Reset(PrepareUdpMessage(node, ip6Addr2, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); SuccessOrQuit(ip4Headers.ParseFrom(*message)); VerifyOrQuit(ip4Headers.GetDestinationAddress() == ip4Addr); VerifyOrQuit(ip4Headers.IsUdp()); VerifyOrQuit(ip4Headers.GetSourcePort() == kSrcPort); VerifyOrQuit(ip4Headers.GetDestinationPort() == kDstPort); VerifyOrQuit(ip4Headers.GetUdpHeader().GetLength() == kPayloadLength); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Ensure a new Address Mapping is created"); iterator.Init(node.GetInstance()); for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++) { LogAddressMapping(mapping); if (AsCoreType(&mapping.mIp6) == ip6Addr) { continue; } VerifyOrQuit(AsCoreType(&mapping.mIp6) == ip6Addr2); VerifyOrQuit(AsCoreType(&mapping.mIp4) == ip4Headers.GetSourceAddress()); VerifyOrQuit(mapping.mRemainingTimeMs > 0); } VerifyOrQuit(count == 2); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Translate another IPv6 message from with previous used addresses"); SuccessOrQuit(ip4Addr.FromString("200.100.1.5")); message.Reset(PrepareUdpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); SuccessOrQuit(ip4Headers.ParseFrom(*message)); VerifyOrQuit(ip4Headers.GetDestinationAddress() == ip4Addr); VerifyOrQuit(ip4Headers.IsUdp()); VerifyOrQuit(ip4Headers.GetSourcePort() == kSrcPort); VerifyOrQuit(ip4Headers.GetDestinationPort() == kDstPort); VerifyOrQuit(ip4Headers.GetUdpHeader().GetLength() == kPayloadLength); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Ensure the previous Address Mapping is reused"); iterator.Init(node.GetInstance()); for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++) { LogAddressMapping(mapping); if (AsCoreType(&mapping.mIp6) == ip6Addr2) { continue; } VerifyOrQuit(AsCoreType(&mapping.mIp6) == ip6Addr); VerifyOrQuit(AsCoreType(&mapping.mIp4) == ip4Headers.GetSourceAddress()); VerifyOrQuit(mapping.mRemainingTimeMs > 0); } VerifyOrQuit(count == 2); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - message.Reset(PrepareUdpMessage(node, ip6Addr2, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); SuccessOrQuit(ip4Headers.ParseFrom(*message)); VerifyOrQuit(ip4Headers.GetDestinationAddress() == ip4Addr); VerifyOrQuit(ip4Headers.IsUdp()); VerifyOrQuit(ip4Headers.GetSourcePort() == kSrcPort); VerifyOrQuit(ip4Headers.GetDestinationPort() == kDstPort); VerifyOrQuit(ip4Headers.GetUdpHeader().GetLength() == kPayloadLength); iterator.Init(node.GetInstance()); for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++) { LogAddressMapping(mapping); if (AsCoreType(&mapping.mIp6) == ip6Addr) { continue; } VerifyOrQuit(AsCoreType(&mapping.mIp6) == ip6Addr2); VerifyOrQuit(AsCoreType(&mapping.mIp4) == ip4Headers.GetSourceAddress()); VerifyOrQuit(mapping.mRemainingTimeMs > 0); } VerifyOrQuit(count == 2); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check Address Mapping expiration and removal"); nexus.AdvanceTime(kExpireTimeout); iterator.Init(node.GetInstance()); VerifyOrQuit(iterator.GetNext(mapping) == kErrorNotFound); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Translate a new IPv6 message and check that a new Address Mapping is created"); message.Reset(PrepareUdpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); SuccessOrQuit(ip4Headers.ParseFrom(*message)); VerifyOrQuit(ip4Headers.GetDestinationAddress() == ip4Addr); VerifyOrQuit(ip4Headers.IsUdp()); VerifyOrQuit(ip4Headers.GetSourcePort() == kSrcPort); VerifyOrQuit(ip4Headers.GetDestinationPort() == kDstPort); VerifyOrQuit(ip4Headers.GetUdpHeader().GetLength() == kPayloadLength); iterator.Init(node.GetInstance()); SuccessOrQuit(iterator.GetNext(mapping)); LogAddressMapping(mapping); VerifyOrQuit(AsCoreType(&mapping.mIp6) == ip6Addr); VerifyOrQuit(AsCoreType(&mapping.mIp4) == ip4Headers.GetSourceAddress()); VerifyOrQuit(mapping.mRemainingTimeMs > 0); VerifyOrQuit(iterator.GetNext(mapping) == kErrorNotFound); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Change the CIDR and check that mapping list is cleared"); SuccessOrQuit(cidr.FromString("192.168.200.0/24")); SuccessOrQuit(node.Get().SetIp4Cidr(cidr)); VerifyOrQuit(node.Get().GetState() == Nat64::kStateActive); iterator.Init(node.GetInstance()); VerifyOrQuit(iterator.GetNext(mapping) == kErrorNotFound); } void TestNat64CidrAddressReuse(const char *aCidr) { static constexpr uint32_t kExpireTimeout = 600 * Time::kOneSecondInMsec; static constexpr uint16_t kSrcPort = 55387; static constexpr uint16_t kDstPort = 55388; static constexpr uint16_t kPayloadLength = 32; Core nexus; Node &node = nexus.CreateNode(); Ip6::Prefix prefix; Ip4::Cidr cidr; uint16_t numIp4Addrs; Nat64::Translator::AddressMappingIterator iterator; Nat64::Translator::AddressMapping mapping; OwnedPtr message; Ip6::Address ip6Addr; Ip4::Address ip4Addr; Ip4::Headers ip4Headers; uint16_t count; Log("------------------------------------------------------------------------------------------------------"); Log("TestNat64CidrAddressReuse(%s)", aCidr); nexus.AdvanceTime(0); node.Form(); nexus.AdvanceTime(50 * Time::kOneSecondInMsec); VerifyOrQuit(node.Get().IsLeader()); SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelInfo)); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Enable NAT64 translator"); SuccessOrQuit(prefix.FromString("fd01::/96")); SuccessOrQuit(cidr.FromString(aCidr)); node.Get().SetNat64Prefix(prefix); SuccessOrQuit(node.Get().SetIp4Cidr(cidr)); node.Get().SetEnabled(true); VerifyOrQuit(node.Get().GetState() == Nat64::kStateActive); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Determine number of available IPv4 addresses"); switch (cidr.GetLength()) { case 32: numIp4Addrs = 1; break; case 31: numIp4Addrs = 2; break; default: numIp4Addrs = (1 << (32 - cidr.GetLength())) - 2; break; } Log("Number of available IPv4 addresses: %u", numIp4Addrs); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Translate IPv6 messages to use all IPv4 addresses"); for (uint16_t i = 0; i < numIp4Addrs; i++) { SuccessOrQuit(ip6Addr.FromString("fd02::0")); SuccessOrQuit(ip4Addr.FromString("200.100.1.1")); ip6Addr.mFields.m8[15] = i; message.Reset(PrepareUdpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); SuccessOrQuit(ip4Headers.ParseFrom(*message)); VerifyOrQuit(ip4Headers.GetDestinationAddress() == ip4Addr); VerifyOrQuit(ip4Headers.IsUdp()); VerifyOrQuit(ip4Headers.GetSourcePort() == kSrcPort); VerifyOrQuit(ip4Headers.GetDestinationPort() == kDstPort); VerifyOrQuit(ip4Headers.GetUdpHeader().GetLength() == kPayloadLength); nexus.AdvanceTime(1000); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check the Address Mappings"); iterator.Init(node.GetInstance()); for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++) { LogAddressMapping(mapping); VerifyOrQuit(mapping.mRemainingTimeMs > 0); } VerifyOrQuit(count == numIp4Addrs); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Validate that next translation fails since all IPv4 addresses are in use"); SuccessOrQuit(ip6Addr.FromString("fd02::100")); message.Reset(PrepareUdpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); VerifyOrQuit(node.Get().TranslateIp6ToIp4(*message) == kErrorDrop); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Wait for mapping entries to expire"); nexus.AdvanceTime(kExpireTimeout); iterator.Init(node.GetInstance()); for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++) { LogAddressMapping(mapping); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Translate IPv6 messages again and check that IPv4 addresses are now reused"); for (uint16_t i = 0; i < numIp4Addrs; i++) { SuccessOrQuit(ip6Addr.FromString("fd02::200:0")); SuccessOrQuit(ip4Addr.FromString("200.100.3.3")); ip6Addr.mFields.m8[15] = i + 100; message.Reset(PrepareTcpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); SuccessOrQuit(ip4Headers.ParseFrom(*message)); VerifyOrQuit(ip4Headers.GetDestinationAddress() == ip4Addr); VerifyOrQuit(ip4Headers.IsTcp()); VerifyOrQuit(ip4Headers.GetSourcePort() == kSrcPort); VerifyOrQuit(ip4Headers.GetDestinationPort() == kDstPort); nexus.AdvanceTime(1000); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check the Address Mappings"); iterator.Init(node.GetInstance()); for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++) { LogAddressMapping(mapping); VerifyOrQuit(mapping.mRemainingTimeMs > 0); } VerifyOrQuit(count == numIp4Addrs); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Validate that next translation fails since all IPv4 addresses are in use"); SuccessOrQuit(ip6Addr.FromString("fd02::200:100")); message.Reset(PrepareTcpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); VerifyOrQuit(node.Get().TranslateIp6ToIp4(*message) == kErrorDrop); Log("End of TestNat64CidrAddressReuse(%s)", aCidr); } void TestNat64Evict(void) { static constexpr uint32_t kEvictTimeout = (120 + 10) * Time::kOneSecondInMsec; static constexpr uint16_t kSrcPort = 55387; static constexpr uint16_t kDstPort = 55388; static constexpr uint16_t kPayloadLength = 32; Core nexus; Node &node = nexus.CreateNode(); Ip6::Prefix prefix; Ip4::Cidr cidr; uint16_t numIp4Addrs; Nat64::Translator::AddressMappingIterator iterator; Nat64::Translator::AddressMapping mapping; OwnedPtr message; Ip6::Address ip6Addr; Ip4::Address ip4Addr; uint16_t count; Log("------------------------------------------------------------------------------------------------------"); Log("TestNat64Evict()"); nexus.AdvanceTime(0); node.Form(); nexus.AdvanceTime(50 * Time::kOneSecondInMsec); VerifyOrQuit(node.Get().IsLeader()); SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelInfo)); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Enable NAT64 translator"); SuccessOrQuit(prefix.FromString("fd00:abba::/96")); SuccessOrQuit(cidr.FromString("192.168.107.0/29")); numIp4Addrs = 6; node.Get().SetNat64Prefix(prefix); SuccessOrQuit(node.Get().SetIp4Cidr(cidr)); node.Get().SetEnabled(true); VerifyOrQuit(node.Get().GetState() == Nat64::kStateActive); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Translate IPv6 messages to use all IPv4 addresses"); SuccessOrQuit(ip6Addr.FromString("fd00:cdef::0")); SuccessOrQuit(ip4Addr.FromString("200.100.2.1")); for (uint16_t i = 0; i < numIp4Addrs; i++) { ip6Addr.mFields.m8[15] = i; message.Reset(PrepareUdpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); nexus.AdvanceTime(1000); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check the Address Mappings"); iterator.Init(node.GetInstance()); for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++) { LogAddressMapping(mapping); VerifyOrQuit(mapping.mRemainingTimeMs > 0); } VerifyOrQuit(count == numIp4Addrs); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Validate that next translation fails since all IPv4 addresses are in use and none can be evicted"); SuccessOrQuit(ip6Addr.FromString("fd00:cdef::ff")); message.Reset(PrepareUdpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); VerifyOrQuit(node.Get().TranslateIp6ToIp4(*message) == kErrorDrop); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Wait for longer than min evict time"); nexus.AdvanceTime(kEvictTimeout); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Now a new transaction should evict the oldest mapping"); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check the Address Mappings and that oldest entry is evicted"); iterator.Init(node.GetInstance()); for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++) { LogAddressMapping(mapping); VerifyOrQuit(mapping.mRemainingTimeMs > 0); VerifyOrQuit(mapping.mIp6.mFields.m8[15] != 0); } VerifyOrQuit(count == numIp4Addrs); Log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ="); node.Get().SetEnabled(false); node.Get().SetEnabled(true); VerifyOrQuit(node.Get().GetState() == Nat64::kStateActive); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Translate IPv6 TCP messages to use all IPv4 addresses"); SuccessOrQuit(ip6Addr.FromString("fd00:cdef::0")); SuccessOrQuit(ip4Addr.FromString("200.100.2.1")); for (uint16_t i = 1; i < numIp4Addrs; i++) { ip6Addr.mFields.m8[15] = i; message.Reset(PrepareTcpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); nexus.AdvanceTime(1000); } Log("Translate one final IPv6 UDP message"); ip6Addr.mFields.m8[15] = 0; message.Reset(PrepareUdpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); nexus.AdvanceTime(1000); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check the Address Mappings"); iterator.Init(node.GetInstance()); for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++) { LogAddressMapping(mapping); VerifyOrQuit(mapping.mRemainingTimeMs > 0); } VerifyOrQuit(count == numIp4Addrs); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Validate that next translation fails since all IPv4 addresses are in use and none can be evicted"); SuccessOrQuit(ip6Addr.FromString("fd00:cdef::ff")); message.Reset(PrepareUdpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); VerifyOrQuit(node.Get().TranslateIp6ToIp4(*message) == kErrorDrop); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Wait for longer than min evict time"); nexus.AdvanceTime(kEvictTimeout); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Now a new transaction should evict the UDP entry"); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check the Address Mappings and that correct entry is evicted"); iterator.Init(node.GetInstance()); for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++) { LogAddressMapping(mapping); VerifyOrQuit(mapping.mRemainingTimeMs > 0); VerifyOrQuit(mapping.mIp6.mFields.m8[15] != 0); } VerifyOrQuit(count == numIp4Addrs); Log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ="); node.Get().SetEnabled(false); node.Get().SetEnabled(true); VerifyOrQuit(node.Get().GetState() == Nat64::kStateActive); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Translate various TCP/UDP messages to use all IPv4 addresses"); SuccessOrQuit(ip6Addr.FromString("fd00:cdef::0")); SuccessOrQuit(ip4Addr.FromString("200.100.2.1")); for (uint16_t i = 1; i < numIp4Addrs - 1; i++) { ip6Addr.mFields.m8[15] = i; message.Reset(PrepareTcpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); nexus.AdvanceTime(1000); } ip6Addr.mFields.m8[15] = numIp4Addrs - 1; message.Reset(PrepareUdpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); nexus.AdvanceTime(1000); Log("Translate one final ICMPv6 message"); ip6Addr.mFields.m8[15] = 0; message.Reset(PrepareIcmp6Message(node, ip6Addr, ip4Addr)); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); nexus.AdvanceTime(1000); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check the Address Mappings"); iterator.Init(node.GetInstance()); for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++) { LogAddressMapping(mapping); VerifyOrQuit(mapping.mRemainingTimeMs > 0); } VerifyOrQuit(count == numIp4Addrs); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Validate that next translation fails since all IPv4 addresses are in use and none can be evicted"); SuccessOrQuit(ip6Addr.FromString("fd00:cdef::ff")); message.Reset(PrepareUdpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength)); VerifyOrQuit(node.Get().TranslateIp6ToIp4(*message) == kErrorDrop); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Wait for longer than min evict time"); nexus.AdvanceTime(kEvictTimeout); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Now a new transaction should evict the ICMP entry"); SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("Check the Address Mappings and that correct entry is evicted"); iterator.Init(node.GetInstance()); for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++) { LogAddressMapping(mapping); VerifyOrQuit(mapping.mRemainingTimeMs > 0); VerifyOrQuit(mapping.mIp6.mFields.m8[15] != 0); } VerifyOrQuit(count == numIp4Addrs); Log("End of TestNat64Evict()"); } void TestNat64IhlBypass(void) { Core nexus; Node &node = nexus.CreateNode(); Ip6::Prefix prefix; Ip4::Cidr cidr; Ip6::Address ip6Addr; Ip4::Address ip4Addr; uint16_t srcPort = 5678; uint16_t dstPort = 1234; uint16_t payloadLen = 10; Log("------------------------------------------------------------------------------------------------------"); Log("TestNat64IhlBypass"); nexus.AdvanceTime(0); node.Form(); nexus.AdvanceTime(50 * Time::kOneSecondInMsec); VerifyOrQuit(node.Get().IsLeader()); SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelInfo)); SuccessOrQuit(prefix.FromString("fd00:7d03:7d03:7d03::/96")); SuccessOrQuit(cidr.FromString("192.168.255.0/24")); node.Get().SetNat64Prefix(prefix); SuccessOrQuit(node.Get().SetIp4Cidr(cidr)); node.Get().SetEnabled(true); // Create a mapping by sending a packet from IPv6 to IPv4 SuccessOrQuit(ip6Addr.FromString("fd00::1")); SuccessOrQuit(ip4Addr.FromString("1.2.3.4")); { Log("Translate an IPv6 message to create mapping"); OwnedPtr message; message.Reset(node.Get().Allocate(Message::kTypeIp6)); VerifyOrQuit(message != nullptr); Ip6::Header ip6Header; ip6Header.Clear(); ip6Header.InitVersionTrafficClassFlow(); ip6Header.SetSource(ip6Addr); ip6Header.GetDestination().SynthesizeFromIp4Address(prefix, ip4Addr); ip6Header.SetNextHeader(Ip6::kProtoUdp); ip6Header.SetPayloadLength(sizeof(Ip6::UdpHeader) + payloadLen); SuccessOrQuit(message->Append(ip6Header)); Ip6::UdpHeader udpHeader; udpHeader.Clear(); udpHeader.SetSourcePort(srcPort); udpHeader.SetDestinationPort(dstPort); udpHeader.SetLength(sizeof(Ip6::UdpHeader) + payloadLen); SuccessOrQuit(message->Append(udpHeader)); for (uint16_t i = 0; i < payloadLen; i++) { SuccessOrQuit(message->Append(0)); } SuccessOrQuit(node.Get().TranslateIp6ToIp4(*message)); } // Now test IPv4 to IPv6 translation with IHL=6 (options) Log("Test 2 (IHL=6, options)"); { OwnedPtr message; message.Reset(node.Get().Allocate(Message::kTypeIp4)); VerifyOrQuit(message != nullptr); Ip4::Header ip4Header; ip4Header.Clear(); // IHL=6 means header length is 6*4 = 24 bytes. ip4Header.SetVersionIhl(0x46); ip4Header.SetTotalLength(24 + sizeof(Ip4::UdpHeader) + payloadLen); ip4Header.SetProtocol(Ip4::kProtoUdp); ip4Header.SetTtl(64); ip4Header.SetSource(ip4Addr); // Find mapped IPv4 address Nat64::Translator::AddressMappingIterator iterator; Nat64::Translator::AddressMapping mapping; iterator.Init(node.GetInstance()); SuccessOrQuit(iterator.GetNext(mapping)); ip4Header.SetDestination(AsCoreType(&mapping.mIp4)); SuccessOrQuit(message->Append(ip4Header)); // Append 4 bytes of options (NOPs) uint8_t options[] = {0x01, 0x01, 0x01, 0x00}; SuccessOrQuit(message->Append(options)); Ip4::UdpHeader udpHeader; udpHeader.Clear(); udpHeader.SetSourcePort(srcPort); udpHeader.SetDestinationPort(dstPort); udpHeader.SetLength(sizeof(Ip4::UdpHeader) + payloadLen); SuccessOrQuit(message->Append(udpHeader)); for (uint16_t i = 0; i < payloadLen; i++) { SuccessOrQuit(message->Append(0)); } SuccessOrQuit(node.Get().TranslateIp4ToIp6(*message)); // Check the translated IPv6 packet Ip6::Headers ip6Headers; SuccessOrQuit(ip6Headers.ParseFrom(*message)); Log("PayloadLength=%d, SrcPort=%d, DstPort=%d", ip6Headers.GetIp6Header().GetPayloadLength(), ip6Headers.GetSourcePort(), ip6Headers.GetDestinationPort()); VerifyOrQuit(ip6Headers.GetSourcePort() == srcPort, "Source port corrupted!"); VerifyOrQuit(ip6Headers.GetDestinationPort() == dstPort, "Destination port corrupted!"); } // Test 3: Source route options should be discarded Log("Test 3 (IHL=7, LSRR option)"); { OwnedPtr message; message.Reset(node.Get().Allocate(Message::kTypeIp4)); VerifyOrQuit(message != nullptr); Ip4::Header ip4Header; ip4Header.Clear(); // IHL=7 means header length is 7*4 = 28 bytes. ip4Header.SetVersionIhl(0x47); ip4Header.SetTotalLength(28 + sizeof(Ip4::UdpHeader) + payloadLen); ip4Header.SetProtocol(Ip4::kProtoUdp); ip4Header.SetTtl(64); ip4Header.SetSource(ip4Addr); // Find mapped IPv4 address Nat64::Translator::AddressMappingIterator iterator; Nat64::Translator::AddressMapping mapping; iterator.Init(node.GetInstance()); SuccessOrQuit(iterator.GetNext(mapping)); ip4Header.SetDestination(AsCoreType(&mapping.mIp4)); SuccessOrQuit(message->Append(ip4Header)); // Append LSRR option (Type 131, Length 8, Pointer 4, Address 1.1.1.1) uint8_t options[] = {0x83, 0x08, 0x04, 0x01, 0x01, 0x01, 0x01, 0x00}; SuccessOrQuit(message->Append(options)); Ip4::UdpHeader udpHeader; udpHeader.Clear(); udpHeader.SetSourcePort(srcPort); udpHeader.SetDestinationPort(dstPort); udpHeader.SetLength(sizeof(Ip4::UdpHeader) + payloadLen); SuccessOrQuit(message->Append(udpHeader)); for (uint16_t i = 0; i < payloadLen; i++) { SuccessOrQuit(message->Append(0)); } // This should return kErrorDrop VerifyOrQuit(node.Get().TranslateIp4ToIp6(*message) == kErrorDrop, "LSRR option not discarded!"); } // Test 4: SSRR option should be discarded Log("Test 4 (IHL=7, SSRR option)"); { OwnedPtr message; message.Reset(node.Get().Allocate(Message::kTypeIp4)); VerifyOrQuit(message != nullptr); Ip4::Header ip4Header; ip4Header.Clear(); // IHL=7 means header length is 7*4 = 28 bytes. ip4Header.SetVersionIhl(0x47); ip4Header.SetTotalLength(28 + sizeof(Ip4::UdpHeader) + payloadLen); ip4Header.SetProtocol(Ip4::kProtoUdp); ip4Header.SetTtl(64); ip4Header.SetSource(ip4Addr); // Find mapped IPv4 address Nat64::Translator::AddressMappingIterator iterator; Nat64::Translator::AddressMapping mapping; iterator.Init(node.GetInstance()); SuccessOrQuit(iterator.GetNext(mapping)); ip4Header.SetDestination(AsCoreType(&mapping.mIp4)); SuccessOrQuit(message->Append(ip4Header)); // Append SSRR option (Type 137, Length 8, Pointer 4, Address 1.1.1.1) uint8_t options[] = {0x89, 0x08, 0x04, 0x01, 0x01, 0x01, 0x01, 0x00}; SuccessOrQuit(message->Append(options)); Ip4::UdpHeader udpHeader; udpHeader.Clear(); udpHeader.SetSourcePort(srcPort); udpHeader.SetDestinationPort(dstPort); udpHeader.SetLength(sizeof(Ip4::UdpHeader) + payloadLen); SuccessOrQuit(message->Append(udpHeader)); for (uint16_t i = 0; i < payloadLen; i++) { SuccessOrQuit(message->Append(0)); } // This should return kErrorDrop VerifyOrQuit(node.Get().TranslateIp4ToIp6(*message) == kErrorDrop, "SSRR option not discarded!"); } } } // namespace Nexus } // namespace ot int main(void) { ot::Nexus::TestNat64StateChanges(); ot::Nexus::TestNat64Mapping(); ot::Nexus::TestNat64CidrAddressReuse("192.168.101.133/32"); ot::Nexus::TestNat64CidrAddressReuse("192.168.102.178/31"); ot::Nexus::TestNat64CidrAddressReuse("192.168.103.0/30"); ot::Nexus::TestNat64CidrAddressReuse("192.168.104.0/27"); ot::Nexus::TestNat64Evict(); ot::Nexus::TestNat64IhlBypass(); printf("All tests passed\n"); return 0; }