mirror of
https://github.com/espressif/openthread.git
synced 2026-08-03 09:27:47 +00:00
[ip6] add method for creating/parsing IPv4-mapped IPv6 address (#9799)
The IPv4-mapped IPv6 address is useful in certain platform/public APIs where we need to support both IPv6 or IPv4 address. We can use IPv4-mapped IPv6 address to represent an IPv4 address. This commit adds simple helper functions to validate, create and parse such addresses.
This commit is contained in:
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (390)
|
||||
#define OPENTHREAD_API_VERSION (391)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -416,6 +416,30 @@ bool otIp4IsAddressEqual(const otIp4Address *aFirst, const otIp4Address *aSecond
|
||||
*/
|
||||
void otIp4ExtractFromIp6Address(uint8_t aPrefixLength, const otIp6Address *aIp6Address, otIp4Address *aIp4Address);
|
||||
|
||||
/**
|
||||
* Extracts the IPv4 address from a given IPv4-mapped IPv6 address.
|
||||
*
|
||||
* An IPv4-mapped IPv6 address consists of an 80-bit prefix of zeros, the next 16 bits set to ones, and the remaining,
|
||||
* least-significant 32 bits contain the IPv4 address, e.g., `::ffff:192.0.2.128` representing `192.0.2.128`.
|
||||
*
|
||||
* @param[in] aIp6Address An IPv6 address to extract IPv4 from.
|
||||
* @param[out] aIp4Address An IPv4 address to output the extracted address.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Extracted the IPv4 address successfully. @p aIp4Address is updated.
|
||||
* @retval OT_ERROR_PARSE The @p aIp6Address does not follow the IPv4-mapped IPv6 address format.
|
||||
*
|
||||
*/
|
||||
otError otIp4FromIp4MappedIp6Address(const otIp6Address *aIp6Address, otIp4Address *aIp4Address);
|
||||
|
||||
/**
|
||||
* Converts a given IP4 address to an IPv6 address following the IPv4-mapped IPv6 address format.
|
||||
*
|
||||
* @param[in] aIp4Address An IPv4 address to convert.
|
||||
* @param[out] aIp6Address An IPv6 address to set.
|
||||
*
|
||||
*/
|
||||
void otIp4ToIp4MappedIp6Address(const otIp4Address *aIp4Address, otIp6Address *aIp6Address);
|
||||
|
||||
#define OT_IP4_ADDRESS_STRING_SIZE 17 ///< Length of 000.000.000.000 plus a suffix NUL
|
||||
|
||||
/**
|
||||
|
||||
@@ -140,6 +140,16 @@ void otIp4ExtractFromIp6Address(uint8_t aPrefixLength, const otIp6Address *aIp6A
|
||||
AsCoreType(aIp4Address).ExtractFromIp6Address(aPrefixLength, AsCoreType(aIp6Address));
|
||||
}
|
||||
|
||||
otError otIp4FromIp4MappedIp6Address(const otIp6Address *aIp6Address, otIp4Address *aIp4Address)
|
||||
{
|
||||
return AsCoreType(aIp4Address).ExtractFromIp4MappedIp6Address(AsCoreType(aIp6Address));
|
||||
}
|
||||
|
||||
void otIp4ToIp4MappedIp6Address(const otIp4Address *aIp4Address, otIp6Address *aIp6Address)
|
||||
{
|
||||
AsCoreType(aIp6Address).SetToIp4Mapped(AsCoreType(aIp4Address));
|
||||
}
|
||||
|
||||
otError otIp4AddressFromString(const char *aString, otIp4Address *aAddress)
|
||||
{
|
||||
AssertPointerIsNotNull(aString);
|
||||
|
||||
@@ -66,6 +66,17 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Address::ExtractFromIp4MappedIp6Address(const Ip6::Address &aIp6Address)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(aIp6Address.IsIp4Mapped(), error = kErrorParse);
|
||||
SetBytes(&aIp6Address.GetBytes()[12]);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Address::ExtractFromIp6Address(uint8_t aPrefixLength, const Ip6::Address &aIp6Address)
|
||||
{
|
||||
// The prefix length must be 32, 40, 48, 56, 64, 96. IPv4 bytes are added
|
||||
|
||||
@@ -122,6 +122,17 @@ public:
|
||||
*/
|
||||
void SetBytes(const uint8_t *aBuffer) { memcpy(mFields.m8, aBuffer, kSize); }
|
||||
|
||||
/**
|
||||
* Sets the IPv4 address from a given IPv4-mapped IPv6 address.
|
||||
*
|
||||
* @param[in] aIp6Address An IPv6 address.
|
||||
*
|
||||
* @retval kErrorNone Set the IPv4 address successfully.
|
||||
* @retval kErrorPase The @p aIp6Address does not follow the IPv4-mapped IPv6 address format.
|
||||
*
|
||||
*/
|
||||
Error ExtractFromIp4MappedIp6Address(const Ip6::Address &aIp6Address);
|
||||
|
||||
/**
|
||||
* Sets the IPv4 address by performing NAT64 address translation from a given IPv6 address as specified
|
||||
* in RFC 6052.
|
||||
|
||||
@@ -388,6 +388,18 @@ bool Address::IsRealmLocalAllMplForwarders(void) const { return (*this == GetRea
|
||||
|
||||
void Address::SetToRealmLocalAllMplForwarders(void) { *this = GetRealmLocalAllMplForwarders(); }
|
||||
|
||||
bool Address::IsIp4Mapped(void) const
|
||||
{
|
||||
return (mFields.m32[0] == 0) && (mFields.m32[1] == 0) && (mFields.m32[2] == BigEndian::HostSwap32(0xffff));
|
||||
}
|
||||
|
||||
void Address::SetToIp4Mapped(const Ip4::Address &aIp4Address)
|
||||
{
|
||||
Clear();
|
||||
mFields.m16[5] = 0xffff;
|
||||
memcpy(&mFields.m8[12], aIp4Address.GetBytes(), sizeof(Ip4::Address));
|
||||
}
|
||||
|
||||
bool Address::MatchesPrefix(const Prefix &aPrefix) const
|
||||
{
|
||||
return Prefix::MatchLength(mFields.m8, aPrefix.GetBytes(), aPrefix.GetBytesSize()) >= aPrefix.GetLength();
|
||||
|
||||
@@ -808,6 +808,27 @@ public:
|
||||
SetToLocator(aNetworkPrefix, aAloc16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether or not the IPv6 address follows the IPv4-mapped format.
|
||||
*
|
||||
* An IPv4-mapped IPv6 address consists of an 80-bit prefix of zeros, the next 16 bits set to ones, and the
|
||||
* remaining, least-significant 32 bits contain the IPv4 address, e.g., `::ffff:192.0.2.128` representing
|
||||
* `192.0.2.128` IPv4 address.
|
||||
*
|
||||
* @retval TRUE If the IPv6 address follows the IPv4-mapped format.
|
||||
* @retval FALSE If the IPv6 address does not follow the IPv4-mapped format.
|
||||
*
|
||||
*/
|
||||
bool IsIp4Mapped(void) const;
|
||||
|
||||
/**
|
||||
* Sets the IPv6 address to follow the IPv4-mapped IPv6 address for a given IPv4 address.
|
||||
*
|
||||
* @param[in] aIp4Address An IPv4 address.
|
||||
*
|
||||
*/
|
||||
void SetToIp4Mapped(const Ip4::Address &aIp4Address);
|
||||
|
||||
/**
|
||||
* Returns the Network Prefix of the IPv6 address (most significant 64 bits of the address).
|
||||
*
|
||||
|
||||
@@ -758,6 +758,44 @@ void TestIp6PrefixTidy(void)
|
||||
}
|
||||
}
|
||||
|
||||
void TestIp4MappedIp6Address(void)
|
||||
{
|
||||
const uint8_t kIp4Address[] = {192, 0, 2, 33};
|
||||
|
||||
const char *kInvalidIp4MappedFormats[] = {
|
||||
"8000::ffff:192.0.2.23", "0:400::ffff:192.0.2.23", "0:0:1::ffff:192.0.2.23", "0:0:0:4:0:ffff:192.0.2.23",
|
||||
"0:0:0:0:1:ffff:192.0.2.23", "::fffe:192.0.2.23", "::efff:192.0.2.23",
|
||||
};
|
||||
|
||||
Ip4::Address expectedIp4Address;
|
||||
Ip4::Address ip4Address;
|
||||
Ip6::Address expectedIp6Address;
|
||||
Ip6::Address ip6Address;
|
||||
|
||||
printf("\nTestIp4MappedIp6Address()\n");
|
||||
|
||||
expectedIp4Address.SetBytes(kIp4Address);
|
||||
|
||||
SuccessOrQuit(expectedIp6Address.FromString("::ffff:192.0.2.33"));
|
||||
ip6Address.SetToIp4Mapped(expectedIp4Address);
|
||||
|
||||
printf("IPv4-mapped IPv6 address: %s\n", ip6Address.ToString().AsCString());
|
||||
|
||||
VerifyOrQuit(ip6Address.IsIp4Mapped());
|
||||
VerifyOrQuit(ip6Address == expectedIp6Address);
|
||||
|
||||
SuccessOrQuit(ip4Address.ExtractFromIp4MappedIp6Address(ip6Address));
|
||||
VerifyOrQuit(ip4Address == expectedIp4Address);
|
||||
|
||||
for (const char *invalidIp4MappedAddr : kInvalidIp4MappedFormats)
|
||||
{
|
||||
SuccessOrQuit(ip6Address.FromString(invalidIp4MappedAddr));
|
||||
printf("Invalid IPv4-mapped IPv6 address: %s -> %s\n", invalidIp4MappedAddr, ip6Address.ToString().AsCString());
|
||||
VerifyOrQuit(!ip6Address.IsIp4Mapped());
|
||||
VerifyOrQuit(ip4Address.ExtractFromIp4MappedIp6Address(ip6Address) != kErrorNone);
|
||||
}
|
||||
}
|
||||
|
||||
void TestIp4Ip6Translation(void)
|
||||
{
|
||||
struct TestCase
|
||||
@@ -884,6 +922,7 @@ int main(void)
|
||||
ot::TestIp6PrefixFromString();
|
||||
ot::TestIp6Prefix();
|
||||
ot::TestIp6PrefixTidy();
|
||||
ot::TestIp4MappedIp6Address();
|
||||
ot::TestIp4Ip6Translation();
|
||||
ot::TestIp4Cidr();
|
||||
ot::TestIp4CidrFromString();
|
||||
|
||||
Reference in New Issue
Block a user