mirror of
https://github.com/espressif/openthread.git
synced 2026-10-11 02:07:40 +00:00
[nat64] add function for parsing IPv4 CIDR (#8954)
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 (309)
|
||||
#define OPENTHREAD_API_VERSION (310)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -435,6 +435,18 @@ void otIp4AddressToString(const otIp4Address *aAddress, char *aBuffer, uint16_t
|
||||
|
||||
#define OT_IP4_CIDR_STRING_SIZE 20 ///< Length of 000.000.000.000/00 plus a suffix NUL
|
||||
|
||||
/**
|
||||
* This function converts a human-readable IPv4 CIDR string into a binary representation.
|
||||
*
|
||||
* @param[in] aString A pointer to a NULL-terminated string.
|
||||
* @param[out] aCidr A pointer to an IPv4 CIDR.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully parsed the string.
|
||||
* @retval OT_ERROR_INVALID_ARGS Failed to parse the string.
|
||||
*
|
||||
*/
|
||||
otError otIp4CidrFromString(const char *aString, otIp4Cidr *aCidr);
|
||||
|
||||
/**
|
||||
* Converts the IPv4 CIDR to a string.
|
||||
*
|
||||
|
||||
@@ -166,6 +166,8 @@ void otIp4AddressToString(const otIp4Address *aAddress, char *aBuffer, uint16_t
|
||||
AsCoreType(aAddress).ToString(aBuffer, aSize);
|
||||
}
|
||||
|
||||
otError otIp4CidrFromString(const char *aString, otIp4Cidr *aCidr) { return AsCoreType(aCidr).FromString(aString); }
|
||||
|
||||
void otIp4CidrToString(const otIp4Cidr *aCidr, char *aBuffer, uint16_t aSize)
|
||||
{
|
||||
AssertPointerIsNotNull(aBuffer);
|
||||
|
||||
@@ -37,10 +37,9 @@
|
||||
namespace ot {
|
||||
namespace Ip4 {
|
||||
|
||||
Error Address::FromString(const char *aString)
|
||||
Error Address::FromString(const char *aString, char aTerminatorChar)
|
||||
{
|
||||
constexpr char kSeparatorChar = '.';
|
||||
constexpr char kNullChar = '\0';
|
||||
|
||||
Error error = kErrorParse;
|
||||
|
||||
@@ -74,7 +73,7 @@ Error Address::FromString(const char *aString)
|
||||
aString++;
|
||||
}
|
||||
|
||||
VerifyOrExit(*aString == kNullChar);
|
||||
VerifyOrExit(*aString == aTerminatorChar);
|
||||
error = kErrorNone;
|
||||
|
||||
exit:
|
||||
@@ -148,6 +147,46 @@ Address::InfoString Address::ToString(void) const
|
||||
return string;
|
||||
}
|
||||
|
||||
Error Cidr::FromString(const char *aString)
|
||||
{
|
||||
constexpr char kSlashChar = '/';
|
||||
constexpr uint16_t kMaxCidrLength = 32;
|
||||
|
||||
Error error = kErrorParse;
|
||||
|
||||
SuccessOrExit(AsCoreType(&mAddress).FromString(aString, kSlashChar));
|
||||
|
||||
aString = StringFind(aString, kSlashChar);
|
||||
VerifyOrExit(aString != nullptr);
|
||||
aString++;
|
||||
|
||||
{
|
||||
uint8_t hasFirstDigit = false;
|
||||
uint16_t value = 0;
|
||||
|
||||
for (char digitChar = *aString;; ++aString, digitChar = *aString)
|
||||
{
|
||||
if ((digitChar < '0') || (digitChar > '9'))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
value = static_cast<uint16_t>((value * 10) + static_cast<uint8_t>(digitChar - '0'));
|
||||
VerifyOrExit(value <= kMaxCidrLength);
|
||||
hasFirstDigit = true;
|
||||
}
|
||||
|
||||
VerifyOrExit(*aString == kNullChar);
|
||||
VerifyOrExit(hasFirstDigit);
|
||||
mLength = static_cast<uint8_t>(value);
|
||||
}
|
||||
|
||||
error = kErrorNone;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Cidr::ToString(StringWriter &aWriter) const
|
||||
{
|
||||
aWriter.Append("%s/%d", AsCoreType(&mAddress).ToString().AsCString(), mLength);
|
||||
|
||||
@@ -148,7 +148,7 @@ public:
|
||||
void SynthesizeFromCidrAndHost(const Cidr &aCidr, uint32_t aHost);
|
||||
|
||||
/**
|
||||
* This method parses an IPv4 address string.
|
||||
* This method parses an IPv4 address string terminated by `aTerminatorChar`.
|
||||
*
|
||||
* The string MUST follow the quad-dotted notation of four decimal values (ranging from 0 to 255 each). For
|
||||
* example, "127.0.0.1"
|
||||
@@ -159,7 +159,7 @@ public:
|
||||
* @retval kErrorParse Failed to parse the IPv4 address string.
|
||||
*
|
||||
*/
|
||||
Error FromString(const char *aString);
|
||||
Error FromString(const char *aString, char aTerminatorChar = kNullChar);
|
||||
|
||||
/**
|
||||
* This method converts the address to a string.
|
||||
@@ -206,6 +206,20 @@ public:
|
||||
*/
|
||||
typedef String<Address::kAddressStringSize + kCidrSuffixSize> InfoString;
|
||||
|
||||
/**
|
||||
* This method converts the IPv4 CIDR string to binary.
|
||||
*
|
||||
* The string format uses quad-dotted notation of four bytes in the address with the length of prefix (e.g.,
|
||||
* "127.0.0.1/32").
|
||||
*
|
||||
* @param[in] aString A pointer to the null-terminated string.
|
||||
*
|
||||
* @retval kErrorNone Successfully parsed the IPv4 CIDR string.
|
||||
* @retval kErrorParse Failed to parse the IPv4 CIDR string.
|
||||
*
|
||||
*/
|
||||
Error FromString(const char *aString);
|
||||
|
||||
/**
|
||||
* This method converts the IPv4 CIDR to a string.
|
||||
*
|
||||
|
||||
@@ -149,9 +149,7 @@ void platformInit(otPlatformConfig *aPlatformConfig)
|
||||
gNetifName[0] = '\0';
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
if ((sscanf(OPENTHREAD_POSIX_CONFIG_NAT64_CIDR, "%" SCNu8 ".%" SCNu8 ".%" SCNu8 ".%" SCNu8 "/%" SCNu8,
|
||||
&gNat64Cidr.mAddress.mFields.m8[0], &gNat64Cidr.mAddress.mFields.m8[1],
|
||||
&gNat64Cidr.mAddress.mFields.m8[2], &gNat64Cidr.mAddress.mFields.m8[3], &gNat64Cidr.mLength)) != 5)
|
||||
if (otIp4CidrFromString(OPENTHREAD_POSIX_CONFIG_NAT64_CIDR, &gNat64Cidr) != OT_ERROR_NONE)
|
||||
{
|
||||
gNat64Cidr.mLength = 0;
|
||||
}
|
||||
|
||||
@@ -194,6 +194,77 @@ void TestIp4AddressFromString(void)
|
||||
}
|
||||
}
|
||||
|
||||
struct CidrTestVector
|
||||
{
|
||||
const char *mString;
|
||||
const uint8_t mAddr[sizeof(otIp4Address)];
|
||||
const uint8_t mLength;
|
||||
ot::Error mError;
|
||||
};
|
||||
|
||||
static void checkCidrFromString(CidrTestVector *aTestVector)
|
||||
{
|
||||
ot::Error error;
|
||||
ot::Ip4::Cidr cidr;
|
||||
|
||||
cidr.Clear();
|
||||
|
||||
error = cidr.FromString(aTestVector->mString);
|
||||
|
||||
printf("%-42s -> %-42s\n", aTestVector->mString,
|
||||
(error == ot::kErrorNone) ? cidr.ToString().AsCString() : "(parse error)");
|
||||
|
||||
VerifyOrQuit(error == aTestVector->mError, "Address::FromString returned unexpected error code");
|
||||
|
||||
if (error == ot::kErrorNone)
|
||||
{
|
||||
VerifyOrQuit(0 == memcmp(cidr.GetBytes(), aTestVector->mAddr, sizeof(aTestVector->mAddr)),
|
||||
"Cidr::FromString parsing failed");
|
||||
VerifyOrQuit(cidr.mLength == aTestVector->mLength, "Cidr::FromString parsing failed");
|
||||
}
|
||||
}
|
||||
|
||||
void TestIp4CidrFromString(void)
|
||||
{
|
||||
CidrTestVector testVectors[] = {
|
||||
{"0.0.0.0/0", {0, 0, 0, 0}, 0, ot::kErrorNone},
|
||||
{"255.255.255.255/32", {255, 255, 255, 255}, 32, ot::kErrorNone},
|
||||
{"127.0.0.1/8", {127, 0, 0, 1}, 8, ot::kErrorNone},
|
||||
{"1.2.3.4/24", {1, 2, 3, 4}, 24, ot::kErrorNone},
|
||||
{"001.002.003.004/20", {1, 2, 3, 4}, 20, ot::kErrorNone},
|
||||
{"00000127.000.000.000001/8", {127, 0, 0, 1}, 8, ot::kErrorNone},
|
||||
// Valid suffix, invalid address
|
||||
{"123.231.0.256/4", {0}, 0, ot::kErrorParse}, // Invalid byte value.
|
||||
{"100123.231.0.256/4", {0}, 0, ot::kErrorParse}, // Invalid byte value.
|
||||
{"1.22.33/4", {0}, 0, ot::kErrorParse}, // Too few bytes.
|
||||
{"1.22.33.44.5/4", {0}, 0, ot::kErrorParse}, // Too many bytes.
|
||||
{"a.b.c.d/4", {0}, 0, ot::kErrorParse}, // Wrong digit char.
|
||||
{"123.23.45 .12/4", {0}, 0, ot::kErrorParse}, // Extra space.
|
||||
{"./4", {0}, 0, ot::kErrorParse}, // Invalid.
|
||||
// valid address, invalid suffix
|
||||
{"1.2.3.4/33", {0}, 0, ot::kErrorParse}, // Prefix length too large
|
||||
{"1.2.3.4/12345678", {0}, 0, ot::kErrorParse}, // Prefix length too large?
|
||||
{"1.2.3.4/-1", {0}, 0, ot::kErrorParse}, // Not even a non-negative integer.
|
||||
{"1.2.3.4/3.14", {0}, 0, ot::kErrorParse}, // Not even a integer.
|
||||
{"1.2.3.4/abcd", {0}, 0, ot::kErrorParse}, // Not even a number.
|
||||
{"1.2.3.4/", {0}, 0, ot::kErrorParse}, // Where is the suffix?
|
||||
{"1.2.3.4", {0}, 0, ot::kErrorParse}, // Where is the suffix?
|
||||
// invalid address and invalid suffix
|
||||
{"123.231.0.256/41", {0}, 0, ot::kErrorParse}, // Invalid byte value.
|
||||
{"100123.231.0.256/abc", {0}, 0, ot::kErrorParse}, // Invalid byte value.
|
||||
{"1.22.33", {0}, 0, ot::kErrorParse}, // Too few bytes.
|
||||
{"1.22.33.44.5/36", {0}, 0, ot::kErrorParse}, // Too many bytes.
|
||||
{"a.b.c.d/99", {0}, 0, ot::kErrorParse}, // Wrong digit char.
|
||||
{"123.23.45 .12", {0}, 0, ot::kErrorParse}, // Extra space.
|
||||
{".", {0}, 0, ot::kErrorParse}, // Invalid.
|
||||
};
|
||||
|
||||
for (CidrTestVector &testVector : testVectors)
|
||||
{
|
||||
checkCidrFromString(&testVector);
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckPrefix(const ot::Ip6::Address &aAddress, const uint8_t *aPrefix, uint8_t aPrefixLength)
|
||||
{
|
||||
// Check the first aPrefixLength bits of aAddress to match the given aPrefix.
|
||||
@@ -583,6 +654,7 @@ int main(void)
|
||||
TestIp6Prefix();
|
||||
TestIp4Ip6Translation();
|
||||
TestIp4Cidr();
|
||||
TestIp4CidrFromString();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user