mirror of
https://github.com/espressif/openthread.git
synced 2026-08-03 09:27:47 +00:00
[ip6-address] add SetFromTranslatedIp4Address() for NAT64 (#6353)
This commit adds `Ip6::Address::SetFromTranslatedIp4Address()` method performing NAT64 address translation from an IPv4 address and a NAT64 prefix to construct a corresponding IPv6 address as specified in RFC 6052. This commit also updates the unit test `test_ip6_address.cpp` to cover the behavior of the newly added method.
This commit is contained in:
@@ -453,6 +453,55 @@ bool Address::MatchesFilter(TypeFilter aFilter) const
|
||||
return matches;
|
||||
}
|
||||
|
||||
void Address::SetFromTranslatedIp4Address(const Prefix &aPrefix, const Ip4::Address &aIp4Address)
|
||||
{
|
||||
// The prefix length must be 32, 40, 48, 56, 64, 96. IPv4 bytes are added
|
||||
// after the prefix, skipping over the bits 64 to 71 (byte at `kSkipIndex`)
|
||||
// which must be set to zero. The suffix is set to zero (per RFC 6502).
|
||||
//
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// |PL| 0-------------32--40--48--56--64--72--80--88--96--104---------|
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// |32| prefix |v4(32) | u | suffix |
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// |40| prefix |v4(24) | u |(8)| suffix |
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// |48| prefix |v4(16) | u | (16) | suffix |
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// |56| prefix |(8)| u | v4(24) | suffix |
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// |64| prefix | u | v4(32) | suffix |
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// |96| prefix | v4(32) |
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
|
||||
enum : uint8_t
|
||||
{
|
||||
kSkipIndex = 8,
|
||||
};
|
||||
|
||||
uint8_t prefixLen = aPrefix.GetLength();
|
||||
uint8_t ip6Index;
|
||||
|
||||
OT_ASSERT((prefixLen == 32) || (prefixLen == 40) || (prefixLen == 48) || (prefixLen == 56) || (prefixLen == 64) ||
|
||||
(prefixLen == 96));
|
||||
|
||||
Clear();
|
||||
SetPrefix(aPrefix);
|
||||
|
||||
ip6Index = prefixLen / CHAR_BIT;
|
||||
|
||||
for (uint8_t i = 0; i < Ip4::Address::kSize; i++)
|
||||
{
|
||||
if (ip6Index == kSkipIndex)
|
||||
{
|
||||
ip6Index++;
|
||||
}
|
||||
|
||||
mFields.m8[ip6Index++] = aIp4Address.GetBytes()[i];
|
||||
}
|
||||
}
|
||||
|
||||
Error Address::FromString(const char *aString)
|
||||
{
|
||||
enum : uint8_t
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "common/equatable.hpp"
|
||||
#include "common/string.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
#include "net/ip4_address.hpp"
|
||||
|
||||
using ot::Encoding::BigEndian::HostSwap16;
|
||||
|
||||
@@ -880,6 +881,19 @@ public:
|
||||
*/
|
||||
bool MatchesFilter(TypeFilter aFilter) const;
|
||||
|
||||
/**
|
||||
* This method sets the IPv6 address by performing NAT64 address translation from a given IPv4 address as specified
|
||||
* in RFC 6052.
|
||||
*
|
||||
* The NAT64 @p aPrefix MUST have one of the following lengths: 32, 40, 48, 56, 64, or 96, otherwise the behavior
|
||||
* of this method is undefined.
|
||||
*
|
||||
* @param[in] aPrefix The prefix to use for IPv4/IPv6 translation.
|
||||
* @param[in] aIp4Address The IPv4 address to translate to IPv6.
|
||||
*
|
||||
*/
|
||||
void SetFromTranslatedIp4Address(const Prefix &aPrefix, const Ip4::Address &aIp4Address);
|
||||
|
||||
/**
|
||||
* This method converts an IPv6 address string to binary.
|
||||
*
|
||||
|
||||
@@ -359,6 +359,56 @@ void TestIp6Prefix(void)
|
||||
}
|
||||
}
|
||||
|
||||
void TestIp4Ip6Translation(void)
|
||||
{
|
||||
struct TestCase
|
||||
{
|
||||
const char *mPrefix; // NAT64 prefix
|
||||
uint8_t mLength; // Prefix length in bits
|
||||
const char *mIp6Address; // Expected IPv6 address (with embedded IPv4 "192.0.2.33").
|
||||
};
|
||||
|
||||
// The test cases are from RFC 6502 - section 2.4
|
||||
|
||||
const TestCase kTestCases[] = {
|
||||
{"2001:db8::", 32, "2001:db8:c000:221::"},
|
||||
{"2001:db8:100::", 40, "2001:db8:1c0:2:21::"},
|
||||
{"2001:db8:122::", 48, "2001:db8:122:c000:2:2100::"},
|
||||
{"2001:db8:122:300::", 56, "2001:db8:122:3c0:0:221::"},
|
||||
{"2001:db8:122:344::", 64, "2001:db8:122:344:c0:2:2100::"},
|
||||
{"2001:db8:122:344::", 96, "2001:db8:122:344::192.0.2.33"},
|
||||
{"64:ff9b::", 96, "64:ff9b::192.0.2.33"},
|
||||
};
|
||||
|
||||
const uint8_t kIp4Address[] = {192, 0, 2, 33};
|
||||
|
||||
ot::Ip4::Address ip4Address;
|
||||
|
||||
printf("\nTestIp4Ip6Translation()\n");
|
||||
|
||||
ip4Address.SetBytes(kIp4Address);
|
||||
|
||||
for (const TestCase &testCase : kTestCases)
|
||||
{
|
||||
ot::Ip6::Prefix prefix;
|
||||
ot::Ip6::Address address;
|
||||
ot::Ip6::Address expectedAddress;
|
||||
|
||||
SuccessOrQuit(address.FromString(testCase.mPrefix), "Ip6::FromString() failed");
|
||||
prefix.Set(address.GetBytes(), testCase.mLength);
|
||||
|
||||
SuccessOrQuit(expectedAddress.FromString(testCase.mIp6Address), "Ip6::FromString() failed");
|
||||
|
||||
address.SetFromTranslatedIp4Address(prefix, ip4Address);
|
||||
|
||||
printf("Prefix: %-26s IPv4Addr: %-12s Ipv6Address: %-36s Expected: %s (%s)\n", prefix.ToString().AsCString(),
|
||||
ip4Address.ToString().AsCString(), address.ToString().AsCString(), testCase.mIp6Address,
|
||||
expectedAddress.ToString().AsCString());
|
||||
|
||||
VerifyOrQuit(address == expectedAddress, "Ip6::SetFromTranslatedIp4Address() failed");
|
||||
}
|
||||
}
|
||||
|
||||
void TestIp6Header(void)
|
||||
{
|
||||
ot::Ip6::Header header;
|
||||
@@ -420,6 +470,7 @@ int main(void)
|
||||
TestIp4AddressFromString();
|
||||
TestIp6AddressFromString();
|
||||
TestIp6Prefix();
|
||||
TestIp4Ip6Translation();
|
||||
TestIp6Header();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user