diff --git a/src/core/net/dns_types.cpp b/src/core/net/dns_types.cpp index b8a9e37e9a2..b2df69ae52f 100644 --- a/src/core/net/dns_types.cpp +++ b/src/core/net/dns_types.cpp @@ -732,7 +732,11 @@ Error Name::ExtractLabels(const char *aName, const char *aSuffixName, char *aLab nameLength -= (suffixLength + 1); VerifyOrExit(nameLength < aLabelsSize, error = kErrorNoBufs); - memcpy(aLabels, aName, nameLength); + if (aLabels != aName) + { + memmove(aLabels, aName, nameLength); + } + aLabels[nameLength] = kNullChar; error = kErrorNone; diff --git a/src/core/net/dns_types.hpp b/src/core/net/dns_types.hpp index 8ca93e13f51..1083ee59eea 100644 --- a/src/core/net/dns_types.hpp +++ b/src/core/net/dns_types.hpp @@ -1028,6 +1028,9 @@ class Name : public Clearable * Both @p aName and @p aSuffixName MUST follow the same style regarding inclusion of trailing dot ('.'). Otherwise * `kErrorParse` is returned. * + * The @p aLabels buffer may be the same as @p aName for in-place label extraction. In this case, the + * implementation avoids unnecessary character copies. + * * @param[in] aName The name to extract labels from. * @param[in] aSuffixName The suffix name (e.g., can be domain name). * @param[out] aLabels Pointer to buffer to copy the extracted labels. @@ -1047,6 +1050,9 @@ class Name : public Clearable * Both @p aName and @p aSuffixName MUST follow the same style regarding inclusion of trailing dot ('.'). Otherwise * `kErrorParse` is returned. * + * The @p aLabels buffer may be the same as @p aName for in-place label extraction. In this case, the + * implementation avoids unnecessary character copies. + * * @tparam kLabelsBufferSize Size of the buffer string. * * @param[in] aName The name to extract labels from. @@ -1064,6 +1070,28 @@ class Name : public Clearable return ExtractLabels(aName, aSuffixName, aLabels, kLabelsBufferSize); } + /** + * Strips a given suffix name (e.g., a domain name) from a given DNS name string, updating it in place. + * + * First checks that @p Name ends with the given @p aSuffixName, otherwise `kErrorParse` is returned. + * + * Both @p aName and @p aSuffixName MUST follow the same style regarding inclusion of trailing dot ('.'). Otherwise + * `kErrorParse` is returned. + * + * @tparam kNameBufferSize The size of name buffer. + * + * @param[in] aName The name buffer to strip the @p aSuffixName from. + * @param[in] aSuffixName The suffix name (e.g., can be domain name). + * + * @retval kErrorNone Successfully stripped the suffix name from @p aName. + * @retval kErrorParse @p aName does not contain @p aSuffixName. + * + */ + template static Error StripName(char (&aName)[kNameBufferSize], const char *aSuffixName) + { + return ExtractLabels(aName, aSuffixName, aName, kNameBufferSize); + } + /** * Tests if a DNS name is a sub-domain of a given domain. * diff --git a/tests/unit/test_dns.cpp b/tests/unit/test_dns.cpp index 4566cde9ca7..e3bac5c4120 100644 --- a/tests/unit/test_dns.cpp +++ b/tests/unit/test_dns.cpp @@ -276,79 +276,77 @@ void TestDnsName(void) printf("----------------------------------------------------------------\n"); printf("Extracting label(s) and removing domains:\n"); - fullName = "my-service._ipps._tcp.default.service.arpa."; - suffixName = "default.service.arpa."; - SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name)); - VerifyOrQuit(strcmp(name, "my-service._ipps._tcp") == 0); - - fullName = "my-service._ipps._tcp.default.service.arpa"; - suffixName = "default.service.arpa"; - SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name)); - VerifyOrQuit(strcmp(name, "my-service._ipps._tcp") == 0); - - fullName = "my-service._ipps._tcp.default.service.arpa"; - suffixName = "default.service.arpa."; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); - - fullName = "my-service._ipps._tcp.default.service.arpa."; - suffixName = "default.service.arpa"; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); - - fullName = "my.service._ipps._tcp.default.service.arpa."; - suffixName = "_ipps._tcp.default.service.arpa."; - SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name)); - VerifyOrQuit(strcmp(name, "my.service") == 0); - - fullName = "my-service._ipps._tcp.default.service.arpa."; - suffixName = "DeFault.SerVice.ARPA."; - SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name)); - VerifyOrQuit(strcmp(name, "my-service._ipps._tcp") == 0); - - fullName = "my-service._ipps._tcp.default.service.arpa"; - suffixName = "DeFault.SerVice.ARPA"; - SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name)); - VerifyOrQuit(strcmp(name, "my-service._ipps._tcp") == 0); - - fullName = "my-service._ipps._tcp.default.service.arpa."; - suffixName = "efault.service.arpa."; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); - - fullName = "my-service._ipps._tcp.default.service.arpa"; - suffixName = "efault.service.arpa"; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); - - fullName = "my-service._ipps._tcp.default.service.arpa."; - suffixName = "xdefault.service.arpa."; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); - - fullName = "my-service._ipps._tcp.default.service.arpa."; - suffixName = ".default.service.arpa."; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); - - fullName = "my-service._ipps._tcp.default.service.arpa."; - suffixName = "default.service.arp."; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); - - fullName = "default.service.arpa."; - suffixName = "default.service.arpa."; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); - - fullName = "default.service.arpa"; - suffixName = "default.service.arpa"; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); - - fullName = "efault.service.arpa."; - suffixName = "default.service.arpa."; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name) == kErrorParse); - - fullName = "my-service._ipps._tcp.default.service.arpa."; - suffixName = "default.service.arpa."; - SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, 22)); - VerifyOrQuit(strcmp(name, "my-service._ipps._tcp") == 0); - - fullName = "my-service._ipps._tcp.default.service.arpa."; - suffixName = "default.service.arpa."; - VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, 21) == kErrorNoBufs); + { + struct TestCase + { + const char *mFullName; + const char *mSuffixName; + const char *mLabels; + }; + + static const TestCase kTestCases[] = { + {"my-service._ipps._tcp.default.service.arpa.", "default.service.arpa.", "my-service._ipps._tcp"}, + {"my-service._ipps._tcp.default.service.arpa", "default.service.arpa", "my-service._ipps._tcp"}, + {"my.service._ipps._tcp.default.service.arpa.", "_ipps._tcp.default.service.arpa.", "my.service"}, + {"my-service._ipps._tcp.default.service.arpa.", "DeFault.SerVice.ARPA.", "my-service._ipps._tcp"}, + {"my-service._ipps._tcp.default.service.arpa", "DeFault.SerVice.ARPA", "my-service._ipps._tcp"}, + + {"my-service._ipps._tcp.default.service.arpa", "default.service.arpa.", nullptr}, + {"my-service._ipps._tcp.default.service.arpa.", "default.service.arpa", nullptr}, + {"my-service._ipps._tcp.default.service.arpa.", "efault.service.arpa.", nullptr}, + {"my-service._ipps._tcp.default.service.arpa", "efault.service.arpa", nullptr}, + {"my-service._ipps._tcp.default.service.arpa.", "xdefault.service.arpa.", nullptr}, + {"my-service._ipps._tcp.default.service.arpa.", ".default.service.arpa.", nullptr}, + {"my-service._ipps._tcp.default.service.arpa.", "default.service.arp.", nullptr}, + {"default.service.arpa.", "default.service.arpa.", nullptr}, + {"default.service.arpa", "default.service.arpa", nullptr}, + {"efault.service.arpa.", "default.service.arpa.", nullptr}, + }; + + for (const TestCase &testCase : kTestCases) + { + Error error; + + printf("\n"); + printf(" FullName : %s\n", testCase.mFullName); + printf(" SuffixName : %s\n", testCase.mSuffixName); + printf(" Extracted labels: %s\n", (testCase.mLabels != nullptr) ? testCase.mLabels : "(parse)"); + + error = Dns::Name::ExtractLabels(testCase.mFullName, testCase.mSuffixName, name); + + if (testCase.mLabels != nullptr) + { + SuccessOrQuit(error); + VerifyOrQuit(strcmp(name, testCase.mLabels) == 0); + } + else + { + VerifyOrQuit(error == kErrorParse); + } + + strcpy(name, testCase.mFullName); + error = Dns::Name::StripName(name, testCase.mSuffixName); + + if (testCase.mLabels != nullptr) + { + SuccessOrQuit(error); + VerifyOrQuit(strcmp(name, testCase.mLabels) == 0); + } + else + { + VerifyOrQuit(error == kErrorParse); + } + } + + fullName = "my-service._ipps._tcp.default.service.arpa."; + suffixName = "default.service.arpa."; + SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, 22)); + VerifyOrQuit(strcmp(name, "my-service._ipps._tcp") == 0); + + fullName = "my-service._ipps._tcp.default.service.arpa."; + suffixName = "default.service.arpa."; + VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, 21) == kErrorNoBufs); + } printf("----------------------------------------------------------------\n"); printf("Append names, check encoded bytes, parse name and read labels:\n");