[nat64] add function for parsing IPv4 CIDR (#8954)

This commit is contained in:
Song GUO
2023-04-17 10:14:08 -07:00
committed by GitHub
parent 25fe46d8dd
commit 9783c14e24
7 changed files with 146 additions and 9 deletions
+1 -1
View File
@@ -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
+12
View File
@@ -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.
*
+2
View File
@@ -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);
+42 -3
View File
@@ -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);
+16 -2
View File
@@ -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.
*
+1 -3
View File
@@ -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;
}
+72
View File
@@ -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;
}