From d1d0dc8aa6f6562131c0a3cce096208fa738e82b Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 5 Apr 2021 08:36:38 -0700 Subject: [PATCH] [dns] allow disabling of DNS name compression for testing (#6368) This commit adds support for "DNS name compression" mode. By default the DNS name compression is enabled. When disabled, DNS names are appended as full and never compressed. This is applicable to OpenThread's DNS and SRP client/server modules. This is intended for testing only and available when config option `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled. This commit also add a CLI command for this feature as `dns compression [enable|disable]` and updates the CLI's `README.md`. --- include/openthread/dns.h | 27 ++++++++ include/openthread/instance.h | 2 +- src/cli/README.md | 27 ++++++++ src/cli/cli.cpp | 118 ++++++++++++++++++++++------------ src/cli/cli.hpp | 4 -- src/core/api/dns_api.cpp | 12 ++++ src/core/common/instance.cpp | 3 + src/core/common/instance.hpp | 27 ++++++++ src/core/net/dns_types.cpp | 25 ++++++- 9 files changed, 197 insertions(+), 48 deletions(-) diff --git a/include/openthread/dns.h b/include/openthread/dns.h index f34322b75..2a5dd1373 100644 --- a/include/openthread/dns.h +++ b/include/openthread/dns.h @@ -38,6 +38,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -140,6 +141,32 @@ void otDnsInitTxtEntryIterator(otDnsTxtEntryIterator *aIterator, const uint8_t * */ otError otDnsGetNextTxtEntry(otDnsTxtEntryIterator *aIterator, otDnsTxtEntry *aEntry); +/** + * This function enables/disables the "DNS name compression" mode. + * + * By default DNS name compression is enabled. When disabled, DNS names are appended as full and never compressed. This + * is applicable to OpenThread's DNS and SRP client/server modules. + * + * This is intended for testing only and available when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` config is enabled. + * + * Note that in the case `OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE` is used, this mode applies to all OpenThread + * instances (i.e., calling this function enables/disables the compression mode on all OpenThread instances). + * + * @param[in] aEnabled TRUE to enable the "DNS name compression" mode, FALSE to disable. + * + */ +void otDnsSetNameCompressionEnabled(bool aEnabled); + +/** + * This function indicates whether the "DNS name compression" mode is enabled or not. + * + * This is intended for testing only and available when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` config is enabled. + * + * @returns TRUE if the "DNS name compression" mode is enabled, FALSE otherwise. + * + */ +bool otDnsIsNameCompressionEnabled(void); + /** * @} * diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 00f5e317f..29919e319 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (92) +#define OPENTHREAD_API_VERSION (93) /** * @addtogroup api-instance diff --git a/src/cli/README.md b/src/cli/README.md index 7641d8090..1c0b4e706 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -991,6 +991,33 @@ Send a service instance resolution DNS query for a given service instance. Servi The parameters after `service-name` are optional. Any unspecified (or zero) value for these optional parameters is replaced by the value from the current default config (`dns config`). +### dns compression \[enable|disable\] + +Enable/Disable the "DNS name compression" mode. + +By default DNS name compression is enabled. When disabled, DNS names are appended as full and never compressed. This is applicable to OpenThread's DNS and SRP client/server modules. + +This is intended for testing only and available under `REFERENCE_DEVICE` config. + +Get the current "DNS name compression" mode. + +``` +> dns compression +Enabled +``` + +Set the "DNS name compression" mode. + +``` +> dns compression disable +Done +> +> +> dns compression +Disabled +Done +``` + ### domainname Get the Thread Domain Name for Thread 1.2 device. diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 8ad91a50a..d17b32650 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -1369,52 +1369,52 @@ void Interpreter::OutputDnsTxtData(const uint8_t *aTxtData, uint16_t aTxtDataLen OutputFormat("]"); } -#if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE - -otError Interpreter::GetDnsConfig(uint8_t aArgsLength, - char * aArgs[], - otDnsQueryConfig *&aConfig, - uint8_t aStartArgsIndex) -{ - // This method gets the optional config from given `aArgs` after the - // `aStartArgsIndex`. The format: `[server IPv6 address] [server - // port] [timeout] [max tx attempt] [recursion desired]`. - - otError error = OT_ERROR_NONE; - bool recursionDesired; - - memset(aConfig, 0, sizeof(otDnsQueryConfig)); - - VerifyOrExit(aArgsLength > aStartArgsIndex, aConfig = nullptr); - - SuccessOrExit(error = ParseAsIp6Address(aArgs[aStartArgsIndex], aConfig->mServerSockAddr.mAddress)); - - VerifyOrExit(aArgsLength > aStartArgsIndex + 1); - SuccessOrExit(error = ParseAsUint16(aArgs[aStartArgsIndex + 1], aConfig->mServerSockAddr.mPort)); - - VerifyOrExit(aArgsLength > aStartArgsIndex + 2); - SuccessOrExit(error = ParseAsUint32(aArgs[aStartArgsIndex + 2], aConfig->mResponseTimeout)); - - VerifyOrExit(aArgsLength > aStartArgsIndex + 3); - SuccessOrExit(error = ParseAsUint8(aArgs[aStartArgsIndex + 3], aConfig->mMaxTxAttempts)); - - VerifyOrExit(aArgsLength > aStartArgsIndex + 4); - SuccessOrExit(error = ParseAsBool(aArgs[aStartArgsIndex + 4], recursionDesired)); - aConfig->mRecursionFlag = recursionDesired ? OT_DNS_FLAG_RECURSION_DESIRED : OT_DNS_FLAG_NO_RECURSION; - -exit: - return error; -} - otError Interpreter::ProcessDns(uint8_t aArgsLength, char *aArgs[]) { - otError error = OT_ERROR_NONE; + OT_UNUSED_VARIABLE(aArgs); + + otError error = OT_ERROR_NONE; +#if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE otDnsQueryConfig queryConfig; otDnsQueryConfig *config = &queryConfig; +#endif - VerifyOrExit(aArgsLength > 0, error = OT_ERROR_INVALID_ARGS); + if (aArgsLength == 0) + { + error = OT_ERROR_INVALID_ARGS; + } +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + else if (strcmp(aArgs[0], "compression") == 0) + { + if (aArgsLength == 1) + { + OutputEnabledDisabledStatus(otDnsIsNameCompressionEnabled()); + } + else + { + bool enable; - if (strcmp(aArgs[0], "config") == 0) + VerifyOrExit(aArgsLength == 2, error = OT_ERROR_INVALID_ARGS); + + if (strcmp(aArgs[1], "enable") == 0) + { + enable = true; + } + else if (strcmp(aArgs[1], "disable") == 0) + { + enable = false; + } + else + { + ExitNow(error = OT_ERROR_INVALID_COMMAND); + } + + otDnsSetNameCompressionEnabled(enable); + } + } +#endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE +#if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE + else if (strcmp(aArgs[0], "config") == 0) { if (aArgsLength == 1) { @@ -1457,6 +1457,7 @@ otError Interpreter::ProcessDns(uint8_t aArgsLength, char *aArgs[]) error = OT_ERROR_PENDING; } #endif // OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE +#endif // OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE else { ExitNow(error = OT_ERROR_INVALID_COMMAND); @@ -1466,6 +1467,43 @@ exit: return error; } +#if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE + +otError Interpreter::GetDnsConfig(uint8_t aArgsLength, + char * aArgs[], + otDnsQueryConfig *&aConfig, + uint8_t aStartArgsIndex) +{ + // This method gets the optional config from given `aArgs` after the + // `aStartArgsIndex`. The format: `[server IPv6 address] [server + // port] [timeout] [max tx attempt] [recursion desired]`. + + otError error = OT_ERROR_NONE; + bool recursionDesired; + + memset(aConfig, 0, sizeof(otDnsQueryConfig)); + + VerifyOrExit(aArgsLength > aStartArgsIndex, aConfig = nullptr); + + SuccessOrExit(error = ParseAsIp6Address(aArgs[aStartArgsIndex], aConfig->mServerSockAddr.mAddress)); + + VerifyOrExit(aArgsLength > aStartArgsIndex + 1); + SuccessOrExit(error = ParseAsUint16(aArgs[aStartArgsIndex + 1], aConfig->mServerSockAddr.mPort)); + + VerifyOrExit(aArgsLength > aStartArgsIndex + 2); + SuccessOrExit(error = ParseAsUint32(aArgs[aStartArgsIndex + 2], aConfig->mResponseTimeout)); + + VerifyOrExit(aArgsLength > aStartArgsIndex + 3); + SuccessOrExit(error = ParseAsUint8(aArgs[aStartArgsIndex + 3], aConfig->mMaxTxAttempts)); + + VerifyOrExit(aArgsLength > aStartArgsIndex + 4); + SuccessOrExit(error = ParseAsBool(aArgs[aStartArgsIndex + 4], recursionDesired)); + aConfig->mRecursionFlag = recursionDesired ? OT_DNS_FLAG_RECURSION_DESIRED : OT_DNS_FLAG_NO_RECURSION; + +exit: + return error; +} + void Interpreter::HandleDnsAddressResponse(otError aError, const otDnsAddressResponse *aResponse, void *aContext) { static_cast(aContext)->HandleDnsAddressResponse(aError, aResponse); diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 8f54fd294..3091d846c 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -374,9 +374,7 @@ private: otError ProcessDiag(uint8_t aArgsLength, char *aArgs[]); #endif otError ProcessDiscover(uint8_t aArgsLength, char *aArgs[]); -#if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE otError ProcessDns(uint8_t aArgsLength, char *aArgs[]); -#endif #if OPENTHREAD_FTD otError ProcessEidCache(uint8_t aArgsLength, char *aArgs[]); #endif @@ -671,9 +669,7 @@ private: {"diag", &Interpreter::ProcessDiag}, #endif {"discover", &Interpreter::ProcessDiscover}, -#if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE {"dns", &Interpreter::ProcessDns}, -#endif #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) {"domainname", &Interpreter::ProcessDomainName}, #endif diff --git a/src/core/api/dns_api.cpp b/src/core/api/dns_api.cpp index 5038a4763..d92c68234 100644 --- a/src/core/api/dns_api.cpp +++ b/src/core/api/dns_api.cpp @@ -52,6 +52,18 @@ otError otDnsGetNextTxtEntry(otDnsTxtEntryIterator *aIterator, otDnsTxtEntry *aE return static_cast(aIterator)->GetNextEntry(*static_cast(aEntry)); } +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE +void otDnsSetNameCompressionEnabled(bool aEnabled) +{ + Instance::SetDnsNameCompressionEnabled(aEnabled); +} + +bool otDnsIsNameCompressionEnabled(void) +{ + return Instance::IsDnsNameCompressionEnabled(); +} +#endif + #if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE const otDnsQueryConfig *otDnsClientGetDefaultConfig(otInstance *aInstance) diff --git a/src/core/common/instance.cpp b/src/core/common/instance.cpp index 1e37ef876..2d5e62bc7 100644 --- a/src/core/common/instance.cpp +++ b/src/core/common/instance.cpp @@ -52,6 +52,9 @@ OT_DEFINE_ALIGNED_VAR(gInstanceRaw, sizeof(Instance), uint64_t); #if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE Utils::Heap Instance::sHeap; #endif +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE +bool Instance::sDnsNameCompressionEnabled = true; +#endif #endif Instance::Instance(void) diff --git a/src/core/common/instance.hpp b/src/core/common/instance.hpp index a4ad5be90..d87f68b16 100644 --- a/src/core/common/instance.hpp +++ b/src/core/common/instance.hpp @@ -283,6 +283,29 @@ public: Coap::CoapSecure &GetApplicationCoapSecure(void) { return mApplicationCoapSecure; } #endif +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + /** + * This method enables/disables the "DNS name compressions" mode. + * + * By default DNS name compression is enabled. When disabled, DNS names are appended as full and never compressed. + * This is applicable to OpenThread's DNS and SRP client/server modules. + * + * This is intended for testing only and available under a `REFERENCE_DEVICE` config. + * + * @param[in] aEnabled TRUE to enable the "DNS name compression" mode, FALSE to disable. + * + */ + static void SetDnsNameCompressionEnabled(bool aEnabled) { sDnsNameCompressionEnabled = aEnabled; } + + /** + * This method indicates whether the "DNS name compression" mode is enabled or not. + * + * @returns TRUE if the "DNS name compressions" mode is enabled, FALSE otherwise. + * + */ + static bool IsDnsNameCompressionEnabled(void) { return sDnsNameCompressionEnabled; } +#endif + #endif // OPENTHREAD_MTD || OPENTHREAD_FTD /** @@ -396,6 +419,10 @@ private: FactoryDiags::Diags mDiags; #endif bool mIsInitialized; + +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD) + static bool sDnsNameCompressionEnabled; +#endif }; // Specializations of the `Get()` method. diff --git a/src/core/net/dns_types.cpp b/src/core/net/dns_types.cpp index ebb0524bf..7f2c4fc4d 100644 --- a/src/core/net/dns_types.cpp +++ b/src/core/net/dns_types.cpp @@ -35,6 +35,7 @@ #include "common/code_utils.hpp" #include "common/debug.hpp" +#include "common/instance.hpp" #include "common/logging.hpp" #include "common/random.hpp" #include "common/string.hpp" @@ -221,6 +222,23 @@ Error Name::AppendTerminator(Message &aMessage) Error Name::AppendPointerLabel(uint16_t aOffset, Message &aMessage) { + Error error; + uint16_t value; + +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + if (!Instance::IsDnsNameCompressionEnabled()) + { + // If "DNS name compression" mode is disabled, instead of + // appending the pointer label, read the name from the message + // and append it uncompressed. Note that the `aOffset` parameter + // in this method is given relative to the start of DNS header + // in `aMessage` (which `aMessage.GetOffset()` specifies). + + error = Name(aMessage, aOffset + aMessage.GetOffset()).AppendTo(aMessage); + ExitNow(); + } +#endif + // A pointer label takes the form of a two byte sequence as a // `uint16_t` value. The first two bits are ones. This allows a // pointer to be distinguished from a text label, since the text @@ -228,13 +246,14 @@ Error Name::AppendPointerLabel(uint16_t aOffset, Message &aMessage) // restricted to 63 octets or less). The next 14-bits specify // an offset value relative to start of DNS header. - uint16_t value; - OT_ASSERT(aOffset < kPointerLabelTypeUint16); value = HostSwap16(aOffset | kPointerLabelTypeUint16); - return aMessage.Append(value); + ExitNow(error = aMessage.Append(value)); + +exit: + return error; } Error Name::AppendName(const char *aName, Message &aMessage)