mirror of
https://github.com/espressif/openthread.git
synced 2026-06-06 05:24:51 +00:00
ab3c6600a0
This commit updates the codebase to use the `Icmp6Header` type directly, replacing the nested `Ip6::Icmp::Header` definition. This change aligns the ICMPv6 header type definition with the conventions used for other network protocol headers and simplifies type references across the network, border router, and utility modules.
1332 lines
50 KiB
C++
1332 lines
50 KiB
C++
/*
|
|
* 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 <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#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<Mle::Mle>().IsLeader());
|
|
|
|
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelInfo));
|
|
|
|
SuccessOrQuit(node.Get<Notifier>().RegisterCallback(HandleNotifierEvent, nullptr));
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Check NAT64 Translator's initial state");
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetState() == Nat64::kStateDisabled);
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetIp4Cidr(cidr) == kErrorNotFound);
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetNat64Prefix(prefix) == kErrorNotFound);
|
|
|
|
iterator.Init(node.GetInstance());
|
|
VerifyOrQuit(iterator.GetNext(mapping) == kErrorNotFound);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Enable NAT64");
|
|
|
|
node.Get<Nat64::Translator>().SetEnabled(true);
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetState() == Nat64::kStateNotRunning);
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetIp4Cidr(cidr) == kErrorNotFound);
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetNat64Prefix(prefix) == kErrorNotFound);
|
|
|
|
iterator.Init(node.GetInstance());
|
|
VerifyOrQuit(iterator.GetNext(mapping) == kErrorNotFound);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Set an invalid CIDR");
|
|
|
|
testCidr.Clear();
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().SetIp4Cidr(testCidr) == kErrorInvalidArgs);
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetState() == Nat64::kStateNotRunning);
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetIp4Cidr(cidr) == kErrorNotFound);
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetNat64Prefix(prefix) == kErrorNotFound);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Set a valid CIDR");
|
|
|
|
SuccessOrQuit(testCidr.FromString("192.168.100.0/8"));
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().SetIp4Cidr(testCidr));
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetState() == Nat64::kStateNotRunning);
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetNat64Prefix(prefix) == kErrorNotFound);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().GetIp4Cidr(cidr));
|
|
VerifyOrQuit(cidr == testCidr);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Set a IPv6 NAT64 prefix");
|
|
|
|
SuccessOrQuit(testPrefix.FromString("fd01::/96"));
|
|
node.Get<Nat64::Translator>().SetNat64Prefix(testPrefix);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().GetNat64Prefix(prefix));
|
|
VerifyOrQuit(prefix == testPrefix);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().GetIp4Cidr(cidr));
|
|
VerifyOrQuit(cidr == testCidr);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Check that NAT64 is now active");
|
|
|
|
nexus.AdvanceTime(1);
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetState() == Nat64::kStateActive);
|
|
|
|
VerifyOrQuit(sNotifierCallbackInvoked);
|
|
VerifyOrQuit(sNotifierEvents & kEventNat64TranslatorStateChanged);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().GetNat64Prefix(prefix));
|
|
VerifyOrQuit(prefix == testPrefix);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().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<Nat64::Translator>().GetState() == Nat64::kStateActive);
|
|
sNotifierCallbackInvoked = false;
|
|
|
|
node.Get<Nat64::Translator>().SetEnabled(false);
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetState() == Nat64::kStateDisabled);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().GetNat64Prefix(prefix));
|
|
VerifyOrQuit(prefix == testPrefix);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().GetIp4Cidr(cidr));
|
|
VerifyOrQuit(cidr == testCidr);
|
|
|
|
nexus.AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sNotifierCallbackInvoked);
|
|
VerifyOrQuit(sNotifierEvents & kEventNat64TranslatorStateChanged);
|
|
|
|
// Re-enable
|
|
|
|
sNotifierCallbackInvoked = false;
|
|
|
|
node.Get<Nat64::Translator>().SetEnabled(true);
|
|
|
|
nexus.AdvanceTime(1);
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetState() == Nat64::kStateActive);
|
|
VerifyOrQuit(sNotifierCallbackInvoked);
|
|
VerifyOrQuit(sNotifierEvents & kEventNat64TranslatorStateChanged);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().GetNat64Prefix(prefix));
|
|
VerifyOrQuit(prefix == testPrefix);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().GetIp4Cidr(cidr));
|
|
VerifyOrQuit(cidr == testCidr);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Set the NAT64 prefix to the same value");
|
|
|
|
nexus.AdvanceTime(1000);
|
|
|
|
node.Get<Nat64::Translator>().SetNat64Prefix(testPrefix);
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetState() == Nat64::kStateActive);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().GetNat64Prefix(prefix));
|
|
VerifyOrQuit(prefix == testPrefix);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().GetIp4Cidr(cidr));
|
|
VerifyOrQuit(cidr == testCidr);
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Clear NAT64 prefix and ensure NAT64 is stopped");
|
|
|
|
nexus.AdvanceTime(1000);
|
|
|
|
sNotifierCallbackInvoked = false;
|
|
node.Get<Nat64::Translator>().ClearNat64Prefix();
|
|
|
|
nexus.AdvanceTime(1);
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetState() == Nat64::kStateNotRunning);
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetNat64Prefix(prefix) == kErrorNotFound);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().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<Nat64::Translator>().SetNat64Prefix(testPrefix);
|
|
|
|
nexus.AdvanceTime(1);
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetState() == Nat64::kStateActive);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().GetNat64Prefix(prefix));
|
|
VerifyOrQuit(prefix == testPrefix);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().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<Nat64::Translator>().ClearIp4Cidr();
|
|
|
|
nexus.AdvanceTime(1);
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetState() == Nat64::kStateNotRunning);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().GetNat64Prefix(prefix));
|
|
VerifyOrQuit(prefix == testPrefix);
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().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<Nat64::Translator>().SetIp4Cidr(testCidr));
|
|
|
|
nexus.AdvanceTime(1);
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().GetState() == Nat64::kStateActive);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().GetNat64Prefix(prefix));
|
|
VerifyOrQuit(prefix == testPrefix);
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().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<MessagePool>().Allocate(Message::kTypeIp6);
|
|
VerifyOrQuit(message != nullptr);
|
|
|
|
ip6Header.Clear();
|
|
ip6Header.InitVersionTrafficClassFlow();
|
|
|
|
ip6Header.SetSource(aSrcIp6Address);
|
|
|
|
SuccessOrQuit(aNode.Get<Nat64::Translator>().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<uint8_t>(static_cast<uint8_t>(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<MessagePool>().Allocate(Message::kTypeIp6);
|
|
VerifyOrQuit(message != nullptr);
|
|
|
|
ip6Header.Clear();
|
|
ip6Header.InitVersionTrafficClassFlow();
|
|
|
|
ip6Header.SetSource(aSrcIp6Address);
|
|
|
|
SuccessOrQuit(aNode.Get<Nat64::Translator>().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<uint8_t>(static_cast<uint8_t>(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<MessagePool>().Allocate(Message::kTypeIp6);
|
|
VerifyOrQuit(message != nullptr);
|
|
|
|
ip6Header.Clear();
|
|
ip6Header.InitVersionTrafficClassFlow();
|
|
|
|
ip6Header.SetSource(aSrcIp6Address);
|
|
|
|
SuccessOrQuit(aNode.Get<Nat64::Translator>().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<uint8_t>(static_cast<uint8_t>(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> 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<Mle::Mle>().IsLeader());
|
|
|
|
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelInfo));
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Enable NAT64 translator");
|
|
|
|
SuccessOrQuit(prefix.FromString("fd01::/96"));
|
|
SuccessOrQuit(cidr.FromString("192.168.100.0/24"));
|
|
|
|
node.Get<Nat64::Translator>().SetNat64Prefix(prefix);
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().SetIp4Cidr(cidr));
|
|
|
|
node.Get<Nat64::Translator>().SetEnabled(true);
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().SetIp4Cidr(cidr));
|
|
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().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> 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<Mle::Mle>().IsLeader());
|
|
|
|
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelInfo));
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Log("Enable NAT64 translator");
|
|
|
|
SuccessOrQuit(prefix.FromString("fd01::/96"));
|
|
SuccessOrQuit(cidr.FromString(aCidr));
|
|
|
|
node.Get<Nat64::Translator>().SetNat64Prefix(prefix);
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().SetIp4Cidr(cidr));
|
|
|
|
node.Get<Nat64::Translator>().SetEnabled(true);
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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> 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<Mle::Mle>().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<Nat64::Translator>().SetNat64Prefix(prefix);
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().SetIp4Cidr(cidr));
|
|
|
|
node.Get<Nat64::Translator>().SetEnabled(true);
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().SetEnabled(false);
|
|
node.Get<Nat64::Translator>().SetEnabled(true);
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().SetEnabled(false);
|
|
node.Get<Nat64::Translator>().SetEnabled(true);
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().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<Nat64::Translator>().TranslateIp6ToIp4(*message));
|
|
nexus.AdvanceTime(1000);
|
|
}
|
|
|
|
ip6Addr.mFields.m8[15] = numIp4Addrs - 1;
|
|
message.Reset(PrepareUdpMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength));
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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<Nat64::Translator>().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<Mle::Mle>().IsLeader());
|
|
|
|
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelInfo));
|
|
|
|
SuccessOrQuit(prefix.FromString("fd00:7d03:7d03:7d03::/96"));
|
|
SuccessOrQuit(cidr.FromString("192.168.255.0/24"));
|
|
node.Get<Nat64::Translator>().SetNat64Prefix(prefix);
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().SetIp4Cidr(cidr));
|
|
node.Get<Nat64::Translator>().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;
|
|
message.Reset(node.Get<MessagePool>().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<uint8_t>(0));
|
|
}
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().TranslateIp6ToIp4(*message));
|
|
}
|
|
|
|
// Now test IPv4 to IPv6 translation with IHL=6 (options)
|
|
Log("Test 2 (IHL=6, options)");
|
|
{
|
|
OwnedPtr<Message> message;
|
|
message.Reset(node.Get<MessagePool>().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<uint8_t>(0));
|
|
}
|
|
|
|
SuccessOrQuit(node.Get<Nat64::Translator>().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;
|
|
message.Reset(node.Get<MessagePool>().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<uint8_t>(0));
|
|
}
|
|
|
|
// This should return kErrorDrop
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().TranslateIp4ToIp6(*message) == kErrorDrop,
|
|
"LSRR option not discarded!");
|
|
}
|
|
|
|
// Test 4: SSRR option should be discarded
|
|
Log("Test 4 (IHL=7, SSRR option)");
|
|
{
|
|
OwnedPtr<Message> message;
|
|
message.Reset(node.Get<MessagePool>().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<uint8_t>(0));
|
|
}
|
|
|
|
// This should return kErrorDrop
|
|
VerifyOrQuit(node.Get<Nat64::Translator>().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;
|
|
}
|