/* * Copyright (c) 2023, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @file * This file implements CLI for DNS (client and server/resolver). */ #include "cli_dns.hpp" #include "cli/cli.hpp" #if OPENTHREAD_CLI_DNS_ENABLE namespace ot { namespace Cli { #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE template <> otError Dns::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; /** * @cli dns compression * @code * dns compression * Enabled * @endcode * @cparam dns compression [@ca{enable|disable}] * @par api_copy * #otDnsIsNameCompressionEnabled * @par * 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." * `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is required. */ if (aArgs[0].IsEmpty()) { OutputEnabledDisabledStatus(otDnsIsNameCompressionEnabled()); } /** * @cli dns compression (enable,disable) * @code * dns compression enable * Enabled * @endcode * @code * dns compression disable * Done * dns compression * Disabled * Done * @endcode * @cparam dns compression [@ca{enable|disable}] * @par * Set the "DNS name compression" mode. * @par * 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." * `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is required. * @sa otDnsSetNameCompressionEnabled */ else { bool enable; SuccessOrExit(error = ParseEnableOrDisable(aArgs[0], enable)); otDnsSetNameCompressionEnabled(enable); } exit: return error; } #endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE #if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE template <> otError Dns::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; /** * @cli dns config * @code * dns config * Server: [fd00:0:0:0:0:0:0:1]:1234 * ResponseTimeout: 5000 ms * MaxTxAttempts: 2 * RecursionDesired: no * ServiceMode: srv * Nat64Mode: allow * Done * @endcode * @par api_copy * #otDnsClientGetDefaultConfig * @par * The config includes the server IPv6 address and port, response * timeout in msec (wait time to rx response), maximum tx attempts * before reporting failure, boolean flag to indicate whether the server * can resolve the query recursively or not. * `OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE` is required. */ if (aArgs[0].IsEmpty()) { const otDnsQueryConfig *defaultConfig = otDnsClientGetDefaultConfig(GetInstancePtr()); OutputFormat("Server: "); OutputSockAddrLine(defaultConfig->mServerSockAddr); OutputLine("ResponseTimeout: %lu ms", ToUlong(defaultConfig->mResponseTimeout)); OutputLine("MaxTxAttempts: %u", defaultConfig->mMaxTxAttempts); OutputLine("RecursionDesired: %s", (defaultConfig->mRecursionFlag == OT_DNS_FLAG_RECURSION_DESIRED) ? "yes" : "no"); OutputLine("ServiceMode: %s", DnsConfigServiceModeToString(defaultConfig->mServiceMode)); #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE OutputLine("Nat64Mode: %s", (defaultConfig->mNat64Mode == OT_DNS_NAT64_ALLOW) ? "allow" : "disallow"); #endif #if OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_ENABLE OutputLine("TransportProtocol: %s", (defaultConfig->mTransportProto == OT_DNS_TRANSPORT_UDP) ? "udp" : "tcp"); #endif } /** * @cli dns config (set) * @code * dns config fd00::1 1234 5000 2 0 * Done * @endcode * @code * dns config * Server: [fd00:0:0:0:0:0:0:1]:1234 * ResponseTimeout: 5000 ms * MaxTxAttempts: 2 * RecursionDesired: no * ServiceMode: srv_txt_opt * Nat64Mode: allow * TransportProtocol: udp * Done * @endcode * @code * dns config fd00::2 * Done * @endcode * @code * dns config * Server: [fd00:0:0:0:0:0:0:2]:53 * ResponseTimeout: 6000 ms * MaxTxAttempts: 3 * RecursionDesired: yes * ServiceMode: srv_txt_opt * Nat64Mode: allow * TransportProtocol: udp * Done * @endcode * @par api_copy * #otDnsClientSetDefaultConfig * @cparam dns config [@ca{dns-server-IP}] [@ca{dns-server-port}] [@ca{response-timeout-ms}] [@ca{max-tx-attempts}] [@ca{recursion-desired-boolean}] [@ca{service-mode}] [@ca{protocol}] * @par * We can leave some of the fields as unspecified (or use value zero). The * unspecified fields are replaced by the corresponding OT config option * definitions `OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT` to form the default * query config. * `OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE` is required. */ else { otDnsQueryConfig queryConfig; otDnsQueryConfig *config = &queryConfig; SuccessOrExit(error = GetDnsConfig(aArgs, config)); otDnsClientSetDefaultConfig(GetInstancePtr(), config); } exit: return error; } /** * @cli dns resolve * @code * dns resolve ipv6.google.com * DNS response for ipv6.google.com - 2a00:1450:401b:801:0:0:0:200e TTL: 300 * @endcode * @code * dns resolve example.com 8.8.8.8 * Synthesized IPv6 DNS server address: fdde:ad00:beef:2:0:0:808:808 * DNS response for example.com. - fd4c:9574:3720:2:0:0:5db8:d822 TTL:20456 * Done * @endcode * @cparam dns resolve @ca{hostname} [@ca{dns-server-IP}] [@ca{dns-server-port}] [@ca{response-timeout-ms}] [@ca{max-tx-attempts}] [@ca{recursion-desired-boolean}] * @par api_copy * #otDnsClientResolveAddress * @par * Send DNS Query to obtain IPv6 address for given hostname. * @par * The parameters after hostname are optional. Any unspecified (or zero) value * for these optional parameters is replaced by the value from the current default * config (dns config). * @par * The DNS server IP can be an IPv4 address, which will be synthesized to an * IPv6 address using the preferred NAT64 prefix from the network data. * @par * Note: The command will return InvalidState when the DNS server IP is an IPv4 * address but the preferred NAT64 prefix is unavailable. * `OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE` is required. */ template <> otError Dns::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; otDnsQueryConfig queryConfig; otDnsQueryConfig *config = &queryConfig; VerifyOrExit(!aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); SuccessOrExit(error = GetDnsConfig(aArgs + 1, config)); SuccessOrExit(error = otDnsClientResolveAddress(GetInstancePtr(), aArgs[0].GetCString(), &HandleDnsAddressResponse, this, config)); error = OT_ERROR_PENDING; exit: return error; } #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE template <> otError Dns::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; otDnsQueryConfig queryConfig; otDnsQueryConfig *config = &queryConfig; VerifyOrExit(!aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); SuccessOrExit(error = GetDnsConfig(aArgs + 1, config)); SuccessOrExit(error = otDnsClientResolveIp4Address(GetInstancePtr(), aArgs[0].GetCString(), &HandleDnsAddressResponse, this, config)); error = OT_ERROR_PENDING; exit: return error; } #endif #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE /** * @cli dns browse * @code * dns browse _service._udp.example.com * DNS browse response for _service._udp.example.com. * inst1 * Port:1234, Priority:1, Weight:2, TTL:7200 * Host:host.example.com. * HostAddress:fd00:0:0:0:0:0:0:abcd TTL:7200 * TXT:[a=6531, b=6c12] TTL:7300 * instance2 * Port:1234, Priority:1, Weight:2, TTL:7200 * Host:host.example.com. * HostAddress:fd00:0:0:0:0:0:0:abcd TTL:7200 * TXT:[a=1234] TTL:7300 * Done * @endcode * @code * dns browse _airplay._tcp.default.service.arpa * DNS browse response for _airplay._tcp.default.service.arpa. * Mac mini * Port:7000, Priority:0, Weight:0, TTL:10 * Host:Mac-mini.default.service.arpa. * HostAddress:fd97:739d:386a:1:1c2e:d83c:fcbe:9cf4 TTL:10 * Done * @endcode * @cparam dns browse @ca{service-name} [@ca{dns-server-IP}] [@ca{dns-server-port}] [@ca{response-timeout-ms}] [@ca{max-tx-attempts}] [@ca{recursion-desired-boolean}] * @sa otDnsClientBrowse * @par * Send a browse (service instance enumeration) DNS query to get the list of services for * given service-name * @par * 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`). * @par * Note: The DNS server IP can be an IPv4 address, which will be synthesized to an IPv6 * address using the preferred NAT64 prefix from the network data. The command will return * `InvalidState` when the DNS server IP is an IPv4 address but the preferred NAT64 prefix * is unavailable. When testing DNS-SD discovery proxy, the zone is not `local` and * instead should be `default.service.arpa`. * `OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE` is required. */ template <> otError Dns::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; otDnsQueryConfig queryConfig; otDnsQueryConfig *config = &queryConfig; VerifyOrExit(!aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS); SuccessOrExit(error = GetDnsConfig(aArgs + 1, config)); SuccessOrExit( error = otDnsClientBrowse(GetInstancePtr(), aArgs[0].GetCString(), &HandleDnsBrowseResponse, this, config)); error = OT_ERROR_PENDING; exit: return error; } /** * @cli dns service * @cparam dns service @ca{service-instance-label} @ca{service-name} [@ca{DNS-server-IP}] [@ca{DNS-server-port}] [@ca{response-timeout-ms}] [@ca{max-tx-attempts}] [@ca{recursion-desired-boolean}] * @par api_copy * #otDnsClientResolveService * @par * Send a service instance resolution DNS query for a given service instance. * Service instance label is provided first, followed by the service name * (note that service instance label can contain dot '.' character). * @par * 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`). * @par * Note: The DNS server IP can be an IPv4 address, which will be synthesized * to an IPv6 address using the preferred NAT64 prefix from the network data. * The command will return `InvalidState` when the DNS server IP is an IPv4 * address but the preferred NAT64 prefix is unavailable. * `OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE` is required. */ template <> otError Dns::Process(Arg aArgs[]) { return ProcessService(aArgs, otDnsClientResolveService); } /** * @cli dns servicehost * @cparam dns servicehost @ca{service-instance-label} @ca{service-name} [@ca{DNS-server-IP}] [@ca{DNS-server-port}] [@ca{response-timeout-ms}] [@ca{max-tx-attempts}] [@ca{recursion-desired-boolean}] * @par api_copy * #otDnsClientResolveServiceAndHostAddress * @par * Send a service instance resolution DNS query for a given service instance * with potential follow-up host name resolution. * Service instance label is provided first, followed by the service name * (note that service instance label can contain dot '.' character). * @par * 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`). * @par * Note: The DNS server IP can be an IPv4 address, which will be synthesized * to an IPv6 address using the preferred NAT64 prefix from the network data. * The command will return `InvalidState` when the DNS server IP is an IPv4 * address but the preferred NAT64 prefix is unavailable. * `OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE` is required. */ template <> otError Dns::Process(Arg aArgs[]) { return ProcessService(aArgs, otDnsClientResolveServiceAndHostAddress); } otError Dns::ProcessService(Arg aArgs[], ResolveServiceFn aResolveServiceFn) { otError error = OT_ERROR_NONE; otDnsQueryConfig queryConfig; otDnsQueryConfig *config = &queryConfig; VerifyOrExit(!aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); SuccessOrExit(error = GetDnsConfig(aArgs + 2, config)); SuccessOrExit(error = aResolveServiceFn(GetInstancePtr(), aArgs[0].GetCString(), aArgs[1].GetCString(), &HandleDnsServiceResponse, this, config)); error = OT_ERROR_PENDING; exit: return error; } #endif // OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE //---------------------------------------------------------------------------------------------------------------------- void Dns::OutputResult(otError aError) { Interpreter::GetInterpreter().OutputResult(aError); } otError Dns::GetDnsConfig(Arg aArgs[], otDnsQueryConfig *&aConfig) { // This method gets the optional DNS config from `aArgs[]`. // The format: `[server IP address] [server port] [timeout] // [max tx attempt] [recursion desired] [service mode] // [transport]` otError error = OT_ERROR_NONE; bool recursionDesired; bool nat64Synth; ClearAllBytes(*aConfig); VerifyOrExit(!aArgs[0].IsEmpty(), aConfig = nullptr); SuccessOrExit(error = ParseToIp6Address(GetInstancePtr(), aArgs[0], aConfig->mServerSockAddr.mAddress, nat64Synth)); if (nat64Synth) { OutputFormat("Synthesized IPv6 DNS server address: "); OutputIp6AddressLine(aConfig->mServerSockAddr.mAddress); } VerifyOrExit(!aArgs[1].IsEmpty()); SuccessOrExit(error = aArgs[1].ParseAsUint16(aConfig->mServerSockAddr.mPort)); VerifyOrExit(!aArgs[2].IsEmpty()); SuccessOrExit(error = aArgs[2].ParseAsUint32(aConfig->mResponseTimeout)); VerifyOrExit(!aArgs[3].IsEmpty()); SuccessOrExit(error = aArgs[3].ParseAsUint8(aConfig->mMaxTxAttempts)); VerifyOrExit(!aArgs[4].IsEmpty()); SuccessOrExit(error = aArgs[4].ParseAsBool(recursionDesired)); aConfig->mRecursionFlag = recursionDesired ? OT_DNS_FLAG_RECURSION_DESIRED : OT_DNS_FLAG_NO_RECURSION; VerifyOrExit(!aArgs[5].IsEmpty()); SuccessOrExit(error = ParseDnsServiceMode(aArgs[5], aConfig->mServiceMode)); VerifyOrExit(!aArgs[6].IsEmpty()); if (aArgs[6] == "tcp") { aConfig->mTransportProto = OT_DNS_TRANSPORT_TCP; } else if (aArgs[6] == "udp") { aConfig->mTransportProto = OT_DNS_TRANSPORT_UDP; } else { error = OT_ERROR_INVALID_ARGS; } exit: return error; } const char *const Dns::kServiceModeStrings[] = { "unspec", // OT_DNS_SERVICE_MODE_UNSPECIFIED (0) "srv", // OT_DNS_SERVICE_MODE_SRV (1) "txt", // OT_DNS_SERVICE_MODE_TXT (2) "srv_txt", // OT_DNS_SERVICE_MODE_SRV_TXT (3) "srv_txt_sep", // OT_DNS_SERVICE_MODE_SRV_TXT_SEPARATE (4) "srv_txt_opt", // OT_DNS_SERVICE_MODE_SRV_TXT_OPTIMIZE (5) }; static_assert(OT_DNS_SERVICE_MODE_UNSPECIFIED == 0, "OT_DNS_SERVICE_MODE_UNSPECIFIED value is incorrect"); static_assert(OT_DNS_SERVICE_MODE_SRV == 1, "OT_DNS_SERVICE_MODE_SRV value is incorrect"); static_assert(OT_DNS_SERVICE_MODE_TXT == 2, "OT_DNS_SERVICE_MODE_TXT value is incorrect"); static_assert(OT_DNS_SERVICE_MODE_SRV_TXT == 3, "OT_DNS_SERVICE_MODE_SRV_TXT value is incorrect"); static_assert(OT_DNS_SERVICE_MODE_SRV_TXT_SEPARATE == 4, "OT_DNS_SERVICE_MODE_SRV_TXT_SEPARATE value is incorrect"); static_assert(OT_DNS_SERVICE_MODE_SRV_TXT_OPTIMIZE == 5, "OT_DNS_SERVICE_MODE_SRV_TXT_OPTIMIZE value is incorrect"); const char *Dns::DnsConfigServiceModeToString(otDnsServiceMode aMode) const { return Stringify(aMode, kServiceModeStrings); } otError Dns::ParseDnsServiceMode(const Arg &aArg, otDnsServiceMode &aMode) const { otError error = OT_ERROR_NONE; if (aArg == "def") { aMode = OT_DNS_SERVICE_MODE_UNSPECIFIED; ExitNow(); } for (size_t index = 0; index < OT_ARRAY_LENGTH(kServiceModeStrings); index++) { if (aArg == kServiceModeStrings[index]) { aMode = static_cast(index); ExitNow(); } } error = OT_ERROR_INVALID_ARGS; exit: return error; } void Dns::HandleDnsAddressResponse(otError aError, const otDnsAddressResponse *aResponse, void *aContext) { static_cast(aContext)->HandleDnsAddressResponse(aError, aResponse); } void Dns::HandleDnsAddressResponse(otError aError, const otDnsAddressResponse *aResponse) { char hostName[OT_DNS_MAX_NAME_SIZE]; otIp6Address address; uint32_t ttl; IgnoreError(otDnsAddressResponseGetHostName(aResponse, hostName, sizeof(hostName))); OutputFormat("DNS response for %s - ", hostName); if (aError == OT_ERROR_NONE) { uint16_t index = 0; while (otDnsAddressResponseGetAddress(aResponse, index, &address, &ttl) == OT_ERROR_NONE) { OutputIp6Address(address); OutputFormat(" TTL:%lu ", ToUlong(ttl)); index++; } } OutputNewLine(); OutputResult(aError); } #if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE void Dns::OutputDnsServiceInfo(uint8_t aIndentSize, const otDnsServiceInfo &aServiceInfo) { OutputLine(aIndentSize, "Port:%d, Priority:%d, Weight:%d, TTL:%lu", aServiceInfo.mPort, aServiceInfo.mPriority, aServiceInfo.mWeight, ToUlong(aServiceInfo.mTtl)); OutputLine(aIndentSize, "Host:%s", aServiceInfo.mHostNameBuffer); OutputFormat(aIndentSize, "HostAddress:"); OutputIp6Address(aServiceInfo.mHostAddress); OutputLine(" TTL:%lu", ToUlong(aServiceInfo.mHostAddressTtl)); OutputFormat(aIndentSize, "TXT:"); if (!aServiceInfo.mTxtDataTruncated) { OutputDnsTxtData(aServiceInfo.mTxtData, aServiceInfo.mTxtDataSize); } else { OutputFormat("["); OutputBytes(aServiceInfo.mTxtData, aServiceInfo.mTxtDataSize); OutputFormat("...]"); } OutputLine(" TTL:%lu", ToUlong(aServiceInfo.mTxtDataTtl)); } void Dns::HandleDnsBrowseResponse(otError aError, const otDnsBrowseResponse *aResponse, void *aContext) { static_cast(aContext)->HandleDnsBrowseResponse(aError, aResponse); } void Dns::HandleDnsBrowseResponse(otError aError, const otDnsBrowseResponse *aResponse) { char name[OT_DNS_MAX_NAME_SIZE]; char label[OT_DNS_MAX_LABEL_SIZE]; uint8_t txtBuffer[kMaxTxtDataSize]; otDnsServiceInfo serviceInfo; IgnoreError(otDnsBrowseResponseGetServiceName(aResponse, name, sizeof(name))); OutputLine("DNS browse response for %s", name); if (aError == OT_ERROR_NONE) { uint16_t index = 0; while (otDnsBrowseResponseGetServiceInstance(aResponse, index, label, sizeof(label)) == OT_ERROR_NONE) { OutputLine("%s", label); index++; serviceInfo.mHostNameBuffer = name; serviceInfo.mHostNameBufferSize = sizeof(name); serviceInfo.mTxtData = txtBuffer; serviceInfo.mTxtDataSize = sizeof(txtBuffer); if (otDnsBrowseResponseGetServiceInfo(aResponse, label, &serviceInfo) == OT_ERROR_NONE) { OutputDnsServiceInfo(kIndentSize, serviceInfo); } OutputNewLine(); } } OutputResult(aError); } void Dns::HandleDnsServiceResponse(otError aError, const otDnsServiceResponse *aResponse, void *aContext) { static_cast(aContext)->HandleDnsServiceResponse(aError, aResponse); } void Dns::HandleDnsServiceResponse(otError aError, const otDnsServiceResponse *aResponse) { char name[OT_DNS_MAX_NAME_SIZE]; char label[OT_DNS_MAX_LABEL_SIZE]; uint8_t txtBuffer[kMaxTxtDataSize]; otDnsServiceInfo serviceInfo; IgnoreError(otDnsServiceResponseGetServiceName(aResponse, label, sizeof(label), name, sizeof(name))); OutputLine("DNS service resolution response for %s for service %s", label, name); if (aError == OT_ERROR_NONE) { serviceInfo.mHostNameBuffer = name; serviceInfo.mHostNameBufferSize = sizeof(name); serviceInfo.mTxtData = txtBuffer; serviceInfo.mTxtDataSize = sizeof(txtBuffer); if (otDnsServiceResponseGetServiceInfo(aResponse, &serviceInfo) == OT_ERROR_NONE) { OutputDnsServiceInfo(/* aIndentSize */ 0, serviceInfo); OutputNewLine(); } } OutputResult(aError); } #endif // OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE #endif // OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE template <> otError Dns::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; if (aArgs[0].IsEmpty()) { error = OT_ERROR_INVALID_ARGS; } #if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE /** * @cli dns server upstream * @code * dns server upstream * Enabled * Done * @endcode * @par api_copy * #otDnssdUpstreamQueryIsEnabled */ else if (aArgs[0] == "upstream") { /** * @cli dns server upstream {enable|disable} * @code * dns server upstream enable * Done * @endcode * @cparam dns server upstream @ca{enable|disable} * @par api_copy * #otDnssdUpstreamQuerySetEnabled */ error = ProcessEnableDisable(aArgs + 1, otDnssdUpstreamQueryIsEnabled, otDnssdUpstreamQuerySetEnabled); } #endif // OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE else { ExitNow(error = OT_ERROR_INVALID_COMMAND); } exit: return error; } #endif // OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE otError Dns::Process(Arg aArgs[]) { #define CmdEntry(aCommandString) \ { \ aCommandString, &Dns::Process \ } static constexpr Command kCommands[] = { #if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE && OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE CmdEntry("browse"), #endif #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE CmdEntry("compression"), #endif #if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE CmdEntry("config"), CmdEntry("resolve"), #if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE CmdEntry("resolve4"), #endif #endif // OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE CmdEntry("server"), #endif #if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE && OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE CmdEntry("service"), CmdEntry("servicehost"), #endif }; #undef CmdEntry static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted"); otError error = OT_ERROR_INVALID_COMMAND; const Command *command; if (aArgs[0].IsEmpty() || (aArgs[0] == "help")) { OutputCommandTable(kCommands); ExitNow(error = aArgs[0].IsEmpty() ? error : OT_ERROR_NONE); } command = BinarySearch::Find(aArgs[0].GetCString(), kCommands); VerifyOrExit(command != nullptr); error = (this->*command->mHandler)(aArgs + 1); exit: return error; } } // namespace Cli } // namespace ot #endif // OPENTHREAD_CLI_DNS_ENABLE