[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:
Abtin Keshavarzian
2021-03-29 16:20:42 -07:00
committed by GitHub
parent 4fb42e245b
commit 2e61433825
3 changed files with 114 additions and 0 deletions
+49
View File
@@ -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
+14
View File
@@ -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.
*
+51
View File
@@ -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;