mirror of
https://github.com/espressif/openthread.git
synced 2026-08-03 17:37:46 +00:00
Add initial implementation of DNS Client (#1460)
* [DNS] Initial DNS Client implementation.
This commit is contained in:
committed by
Jonathan Hui
parent
0c95d6506e
commit
3316daa43c
+7
-7
@@ -37,7 +37,7 @@ set -x
|
||||
[ $BUILD_TARGET != pretty-check ] || {
|
||||
export PATH=/tmp/astyle/build/gcc/bin:$PATH || die
|
||||
./bootstrap || die
|
||||
./configure --enable-ftd --enable-cli --enable-diag --enable-dhcp6-client --enable-dhcp6-server --enable-commissioner --enable-joiner --with-examples=posix || die
|
||||
./configure --enable-ftd --enable-cli --enable-diag --enable-dhcp6-client --enable-dhcp6-server --enable-dns-client --enable-commissioner --enable-joiner --with-examples=posix || die
|
||||
make pretty-check || die
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ set -x
|
||||
git checkout -- . || die
|
||||
git clean -xfd || die
|
||||
./bootstrap || die
|
||||
COMMISSIONER=1 JOINER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 make -f examples/Makefile-cc2538 || die
|
||||
COMMISSIONER=1 JOINER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 make -f examples/Makefile-cc2538 || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-cli-ftd || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-cli-mtd || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-ncp-ftd || die
|
||||
@@ -62,7 +62,7 @@ set -x
|
||||
git checkout -- . || die
|
||||
git clean -xfd || die
|
||||
./bootstrap || die
|
||||
COMMISSIONER=1 JOINER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 make -f examples/Makefile-da15000 || die
|
||||
COMMISSIONER=1 JOINER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 make -f examples/Makefile-da15000 || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-cli-ftd || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-cli-mtd || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-ncp-ftd || die
|
||||
@@ -71,7 +71,7 @@ set -x
|
||||
git checkout -- . || die
|
||||
git clean -xfd || die
|
||||
./bootstrap || die
|
||||
COMMISSIONER=1 JOINER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 make -f examples/Makefile-nrf52840 || die
|
||||
COMMISSIONER=1 JOINER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 make -f examples/Makefile-nrf52840 || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-cli-ftd || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-cli-mtd || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-ncp-ftd || die
|
||||
@@ -91,7 +91,7 @@ set -x
|
||||
git checkout -- . || die
|
||||
git clean -xfd || die
|
||||
./bootstrap || die
|
||||
COMMISSIONER=1 JOINER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 make -f examples/Makefile-cc2538 || die
|
||||
COMMISSIONER=1 JOINER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 make -f examples/Makefile-cc2538 || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-cli-ftd || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-cli-mtd || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-ncp-ftd || die
|
||||
@@ -100,7 +100,7 @@ set -x
|
||||
git checkout -- . || die
|
||||
git clean -xfd || die
|
||||
./bootstrap || die
|
||||
COMMISSIONER=1 JOINER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 make -f examples/Makefile-da15000 || die
|
||||
COMMISSIONER=1 JOINER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 make -f examples/Makefile-da15000 || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-cli-ftd || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-cli-mtd || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-ncp-ftd || die
|
||||
@@ -109,7 +109,7 @@ set -x
|
||||
git checkout -- . || die
|
||||
git clean -xfd || die
|
||||
./bootstrap || die
|
||||
COMMISSIONER=1 JOINER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 make -f examples/Makefile-nrf52840 || die
|
||||
COMMISSIONER=1 JOINER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 DNS_CLIENT=1 make -f examples/Makefile-nrf52840 || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-cli-ftd || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-cli-mtd || die
|
||||
arm-none-eabi-size output/bin/arm-none-eabi-ot-ncp-ftd || die
|
||||
|
||||
@@ -41,6 +41,7 @@ AM_DISTCHECK_CONFIGURE_FLAGS = \
|
||||
--enable-joiner \
|
||||
--enable-dhcp6-client \
|
||||
--enable-dhcp6-server \
|
||||
--enable-dns-client \
|
||||
$(NULL)
|
||||
|
||||
SUBDIRS = \
|
||||
|
||||
@@ -758,6 +758,36 @@ AC_SUBST(OPENTHREAD_ENABLE_DHCP6_SERVER)
|
||||
AM_CONDITIONAL([OPENTHREAD_ENABLE_DHCP6_SERVER], [test "${enable_dhcp6_server}" = "yes"])
|
||||
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_DHCP6_SERVER],[${OPENTHREAD_ENABLE_DHCP6_SERVER}],[Define to 1 if you want to enable DHCPv6 Server])
|
||||
|
||||
#
|
||||
# DNS Client
|
||||
#
|
||||
|
||||
AC_ARG_ENABLE(dns_client,
|
||||
[AS_HELP_STRING([--enable-dns-client],[Enable DNS client support @<:@default=no@:>@.])],
|
||||
[
|
||||
case "${enableval}" in
|
||||
|
||||
no|yes)
|
||||
enable_dns_client=${enableval}
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_ERROR([Invalid value ${enable_dns_client} for --enable-dns-client])
|
||||
;;
|
||||
esac
|
||||
],
|
||||
[enable_dns_client=no])
|
||||
|
||||
if test "$enable_dns_client" = "yes"; then
|
||||
OPENTHREAD_ENABLE_DNS_CLIENT=1
|
||||
else
|
||||
OPENTHREAD_ENABLE_DNS_CLIENT=0
|
||||
fi
|
||||
|
||||
AC_SUBST(OPENTHREAD_ENABLE_DNS_CLIENT)
|
||||
AM_CONDITIONAL([OPENTHREAD_ENABLE_DNS_CLIENT], [test "${enable_dns_client}" = "yes"])
|
||||
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_DNS_CLIENT],[${OPENTHREAD_ENABLE_DNS_CLIENT}],[Define to 1 if you want to enable DNS Client])
|
||||
|
||||
#
|
||||
# Application CoAP
|
||||
#
|
||||
@@ -1109,6 +1139,7 @@ AC_MSG_NOTICE([
|
||||
OpenThread Certification log support : ${enable_cert_log}
|
||||
OpenThread DHCPv6 Server support : ${enable_dhcp6_server}
|
||||
OpenThread DHCPv6 Client support : ${enable_dhcp6_client}
|
||||
OpenThread DNS Client support : ${enable_dns_client}
|
||||
Openthread Application CoAP support : ${enable_application_coap}
|
||||
Openthread Raw Link-Layer support : ${enable_raw_link_api}
|
||||
OpenThread examples : ${OPENTHREAD_EXAMPLES}
|
||||
|
||||
@@ -91,8 +91,12 @@ ifeq ($(DHCP6_CLIENT),1)
|
||||
configure_OPTIONS += --enable-dhcp6-client
|
||||
endif
|
||||
|
||||
ifeq ($(DNS_CLIENT),1)
|
||||
configure_OPTIONS += --enable-dns-client
|
||||
endif
|
||||
|
||||
ifeq ($(COVERAGE),1)
|
||||
configure_OPTIONS += --enable-coverage --enable-commissioner --enable-joiner --enable-dhcp6-client --enable-dhcp6-server
|
||||
configure_OPTIONS += --enable-coverage --enable-commissioner --enable-joiner --enable-dhcp6-client --enable-dhcp6-server --enable-dns-client
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
|
||||
@@ -95,7 +95,7 @@ configure_OPTIONS = \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(COVERAGE),1)
|
||||
configure_OPTIONS += --enable-coverage --enable-commissioner --enable-joiner --enable-dhcp6-client --enable-dhcp6-server
|
||||
configure_OPTIONS += --enable-coverage --enable-commissioner --enable-joiner --enable-dhcp6-client --enable-dhcp6-server --enable-dns-client
|
||||
else
|
||||
configure_OPTIONS +=
|
||||
endif
|
||||
@@ -295,4 +295,3 @@ help:
|
||||
$(ECHO) ""
|
||||
$(ECHO) " $(TargetTuple)"
|
||||
$(ECHO) ""
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ openthread_headers = \
|
||||
diag.h \
|
||||
dhcp6_client.h \
|
||||
dhcp6_server.h \
|
||||
dns.h \
|
||||
icmp6.h \
|
||||
instance.h \
|
||||
ip6.h \
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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
|
||||
* @brief
|
||||
* This file defines the top-level dns functions for the OpenThread library.
|
||||
*/
|
||||
|
||||
#ifndef OPENTHREAD_DNS_H_
|
||||
#define OPENTHREAD_DNS_H_
|
||||
|
||||
#include <openthread/types.h>
|
||||
#include <openthread/message.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup dns DNS
|
||||
*
|
||||
* @brief
|
||||
* This module includes functions that control DNS communication.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
#define OT_DNS_MAX_HOSTNAME_LENGTH 62 ///< Maximum allowed hostname length (maximum label size - 1 for compression).
|
||||
|
||||
#define OT_DNS_DEFAULT_DNS_SERVER_IP "2001:4860:4860::8888" ///< Defines default DNS Server address - Google DNS.
|
||||
#define OT_DNS_DEFAULT_DNS_SERVER_PORT 53 ///< Defines default DNS Server port.
|
||||
|
||||
/**
|
||||
* This structure implements DNS Query parameters.
|
||||
*
|
||||
*/
|
||||
typedef struct otDnsQuery
|
||||
{
|
||||
const char *mHostname; ///< Identifies hostname to be found. It shall not change during resolving.
|
||||
const otMessageInfo *mMessageInfo; ///< A reference to the message info related with DNS Server.
|
||||
bool mNoRecursion; ///< If cleared, it directs name server to pursue the query recursively.
|
||||
} otDnsQuery;
|
||||
|
||||
/**
|
||||
* This function pointer is called when a DNS response is received.
|
||||
*
|
||||
* @param[in] aContext A pointer to application-specific context.
|
||||
* @param[in] aHostname Identifies hostname related with DNS response.
|
||||
* @param[in] aAddress A pointer to the IPv6 address received in DNS response. May be null.
|
||||
* @param[in] aTtl Specifies the maximum time in seconds that the resource record may be cached.
|
||||
* @param[in] aResult A result of the DNS transaction.
|
||||
*
|
||||
* @retval kThreadError_None A response was received successfully and IPv6 address is provided
|
||||
* in @p aAddress.
|
||||
* @retval kThreadError_Abort A DNS transaction was aborted by stack.
|
||||
* @retval kThreadError_ResponseTimeout No DNS response has been received within timeout.
|
||||
* @retval kThreadError_NotFound A response was received but no IPv6 address has been found.
|
||||
* @retval kThreadError_Failed A response was received but status code is different than success.
|
||||
*
|
||||
*/
|
||||
typedef void (*otDnsResponseHandler)(void *aContext, const char *aHostname, otIp6Address *aAddress,
|
||||
uint32_t aTtl, ThreadError aResult);
|
||||
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
/**
|
||||
* This function sends a DNS query for AAAA (IPv6) record.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aQuery A pointer to specify DNS query parameters.
|
||||
* @param[in] aHandler A function pointer that shall be called on response reception or time-out.
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
*
|
||||
*/
|
||||
ThreadError otDnsClientQuery(otInstance *aInstance, const otDnsQuery *aQuery, otDnsResponseHandler aHandler,
|
||||
void *aContext);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_DNS_H_
|
||||
@@ -185,7 +185,7 @@ typedef enum ThreadError
|
||||
kThreadError_NotCapable = 29,
|
||||
|
||||
/**
|
||||
* Coap response or acknowledgment not received.
|
||||
* Coap response or acknowledgment or DNS response not received.
|
||||
*/
|
||||
kThreadError_ResponseTimeout = 30,
|
||||
|
||||
|
||||
+14
-1
@@ -20,6 +20,7 @@ OpenThread test scripts use the CLI to execute test cases.
|
||||
* [dataset](#dataset-help)
|
||||
* [delaytimermin](#delaytimermin)
|
||||
* [discover](#discover-channel)
|
||||
* [dns](#dns-resolve-hostname-dns-server-ip-dns-server-port)
|
||||
* [eidcache](#eidcache)
|
||||
* [eui64](#eui64)
|
||||
* [extaddr](#extaddr)
|
||||
@@ -463,7 +464,7 @@ pendingtimestamp
|
||||
pskc
|
||||
securitypolicy
|
||||
Done
|
||||
>
|
||||
>
|
||||
```
|
||||
|
||||
### dataset active
|
||||
@@ -686,6 +687,18 @@ Perform an MLE Discovery operation.
|
||||
Done
|
||||
```
|
||||
|
||||
### dns resolve \<hostname\> \[DNS server IP\] \[DNS server port\]
|
||||
|
||||
Send DNS Query to obtain IPv6 address for given hostname.
|
||||
The latter two parameters have following default values:
|
||||
* DNS server IP: 2001:4860:4860::8888 (Google DNS Server)
|
||||
* DNS server port: 53
|
||||
|
||||
```bash
|
||||
> dns resolve ipv6.google.com
|
||||
> DNS response for ipv6.google.com - [2a00:1450:401b:801:0:0:0:200e] TTL: 300
|
||||
```
|
||||
|
||||
### eidcache
|
||||
|
||||
Print the EID-to-RLOC cache entries.
|
||||
|
||||
+101
@@ -95,6 +95,9 @@ const struct Command Interpreter::sCommands[] =
|
||||
{ "diag", &Interpreter::ProcessDiag },
|
||||
#endif
|
||||
{ "discover", &Interpreter::ProcessDiscover },
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
{ "dns", &Interpreter::ProcessDns },
|
||||
#endif
|
||||
{ "eidcache", &Interpreter::ProcessEidCache },
|
||||
{ "eui64", &Interpreter::ProcessEui64 },
|
||||
#ifdef OPENTHREAD_EXAMPLES_POSIX
|
||||
@@ -193,6 +196,9 @@ Interpreter::Interpreter(otInstance *aInstance):
|
||||
sCount(1),
|
||||
sInterval(1000),
|
||||
sPingTimer(aInstance->mIp6.mTimerScheduler, &Interpreter::s_HandlePingTimer, this),
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
mResolvingInProgress(0),
|
||||
#endif
|
||||
#endif
|
||||
mInstance(aInstance)
|
||||
{
|
||||
@@ -211,6 +217,11 @@ Interpreter::Interpreter(otInstance *aInstance):
|
||||
#if OPENTHREAD_ENABLE_DHCP6_CLIENT
|
||||
memset(mDhcpAddresses, 0, sizeof(mDhcpAddresses));
|
||||
#endif // OPENTHREAD_ENABLE_DHCP6_CLIENT
|
||||
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
memset(mResolvingHostname, 0, sizeof(mResolvingHostname));
|
||||
#endif // OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -708,6 +719,96 @@ exit:
|
||||
AppendResult(error);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
void Interpreter::ProcessDns(int argc, char *argv[])
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
long port = OT_DNS_DEFAULT_DNS_SERVER_PORT;
|
||||
Ip6::MessageInfo messageInfo;
|
||||
otDnsQuery query;
|
||||
|
||||
VerifyOrExit(argc > 0, error = kThreadError_InvalidArgs);
|
||||
|
||||
if (strcmp(argv[0], "resolve") == 0)
|
||||
{
|
||||
VerifyOrExit(!mResolvingInProgress, error = kThreadError_Busy);
|
||||
VerifyOrExit(argc > 1, error = kThreadError_InvalidArgs);
|
||||
VerifyOrExit(strlen(argv[1]) < OT_DNS_MAX_HOSTNAME_LENGTH, error = kThreadError_InvalidArgs);
|
||||
|
||||
strcpy(mResolvingHostname, argv[1]);
|
||||
|
||||
memset(&messageInfo, 0, sizeof(messageInfo));
|
||||
messageInfo.mInterfaceId = OT_NETIF_INTERFACE_ID_THREAD;
|
||||
|
||||
if (argc > 2)
|
||||
{
|
||||
SuccessOrExit(error = messageInfo.GetPeerAddr().FromString(argv[2]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use IPv6 address of default DNS server.
|
||||
SuccessOrExit(error = messageInfo.GetPeerAddr().FromString(OT_DNS_DEFAULT_DNS_SERVER_IP));
|
||||
}
|
||||
|
||||
if (argc > 3)
|
||||
{
|
||||
SuccessOrExit(error = ParseLong(argv[3], port));
|
||||
}
|
||||
|
||||
messageInfo.SetPeerPort(static_cast<uint16_t>(port));
|
||||
|
||||
query.mHostname = mResolvingHostname;
|
||||
query.mMessageInfo = static_cast<const otMessageInfo *>(&messageInfo);
|
||||
query.mNoRecursion = false;
|
||||
|
||||
SuccessOrExit(error = otDnsClientQuery(mInstance, &query, &Interpreter::s_HandleDnsResponse, this));
|
||||
|
||||
mResolvingInProgress = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitNow(error = kThreadError_InvalidArgs);
|
||||
}
|
||||
|
||||
exit:
|
||||
AppendResult(error);
|
||||
}
|
||||
|
||||
void Interpreter::s_HandleDnsResponse(void *aContext, const char *aHostname, otIp6Address *aAddress,
|
||||
uint32_t aTtl, ThreadError aResult)
|
||||
{
|
||||
static_cast<Interpreter *>(aContext)->HandleDnsResponse(aHostname,
|
||||
*static_cast<Ip6::Address *>(aAddress),
|
||||
aTtl, aResult);
|
||||
}
|
||||
|
||||
void Interpreter::HandleDnsResponse(const char *aHostname, Ip6::Address &aAddress, uint32_t aTtl, ThreadError aResult)
|
||||
{
|
||||
sServer->OutputFormat("DNS response for %s - ", aHostname);
|
||||
|
||||
if (aResult == kThreadError_None)
|
||||
{
|
||||
sServer->OutputFormat("[%x:%x:%x:%x:%x:%x:%x:%x] TTL: %d\r\n",
|
||||
HostSwap16(aAddress.mFields.m16[0]),
|
||||
HostSwap16(aAddress.mFields.m16[1]),
|
||||
HostSwap16(aAddress.mFields.m16[2]),
|
||||
HostSwap16(aAddress.mFields.m16[3]),
|
||||
HostSwap16(aAddress.mFields.m16[4]),
|
||||
HostSwap16(aAddress.mFields.m16[5]),
|
||||
HostSwap16(aAddress.mFields.m16[6]),
|
||||
HostSwap16(aAddress.mFields.m16[7]),
|
||||
aTtl);
|
||||
}
|
||||
else
|
||||
{
|
||||
AppendResult(aResult);
|
||||
}
|
||||
|
||||
mResolvingInProgress = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Interpreter::ProcessEidCache(int argc, char *argv[])
|
||||
{
|
||||
otEidCacheEntry entry;
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include <net/icmp6.hpp>
|
||||
#include <common/timer.hpp>
|
||||
#include "openthread/dhcp6_client.h"
|
||||
#include "openthread/dns.h"
|
||||
#endif
|
||||
|
||||
#ifdef OTDLL
|
||||
@@ -172,6 +173,9 @@ private:
|
||||
void ProcessDiag(int argc, char *argv[]);
|
||||
#endif // OPENTHREAD_ENABLE_DIAG
|
||||
void ProcessDiscover(int argc, char *argv[]);
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
void ProcessDns(int argc, char *argv[]);
|
||||
#endif
|
||||
void ProcessEidCache(int argc, char *argv[]);
|
||||
void ProcessEui64(int argc, char *argv[]);
|
||||
#ifdef OPENTHREAD_EXAMPLES_POSIX
|
||||
@@ -257,6 +261,11 @@ private:
|
||||
#endif
|
||||
static void OTCALL s_HandleJoinerCallback(ThreadError aError, void *aContext);
|
||||
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
static void s_HandleDnsResponse(void *aContext, const char *aHostname, otIp6Address *aAddress,
|
||||
uint32_t aTtl, ThreadError aResult);
|
||||
#endif
|
||||
|
||||
#ifndef OTDLL
|
||||
void HandleIcmpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo,
|
||||
const Ip6::IcmpHeader &aIcmpHeader);
|
||||
@@ -278,6 +287,10 @@ private:
|
||||
#endif
|
||||
void HandleJoinerCallback(ThreadError aError);
|
||||
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
void HandleDnsResponse(const char *aHostname, Ip6::Address &aAddress, uint32_t aTtl, ThreadError aResult);
|
||||
#endif
|
||||
|
||||
static const struct Command sCommands[];
|
||||
|
||||
Server *sServer;
|
||||
@@ -312,6 +325,11 @@ private:
|
||||
#endif // OPENTHREAD_ENABLE_DHCP6_CLIENT
|
||||
|
||||
otIcmp6Handler mIcmpHandler;
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
bool mResolvingInProgress;
|
||||
char mResolvingHostname[OT_DNS_MAX_HOSTNAME_LENGTH];
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
otInstance *mInstance;
|
||||
|
||||
+13
-4
@@ -147,6 +147,13 @@ SOURCES_COMMON += \
|
||||
$(NULL)
|
||||
endif # OPENTHREAD_ENABLE_DHCP6_SERVER
|
||||
|
||||
if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
SOURCES_COMMON += \
|
||||
api/dns_api.cpp \
|
||||
net/dns_client.cpp \
|
||||
$(NULL)
|
||||
endif # OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
|
||||
if OPENTHREAD_ENABLE_JAM_DETECTION
|
||||
SOURCES_COMMON += \
|
||||
api/jam_detection_api.cpp \
|
||||
@@ -249,6 +256,11 @@ noinst_HEADERS = \
|
||||
meshcop/panid_query_client.hpp \
|
||||
meshcop/timestamp.hpp \
|
||||
meshcop/tlvs.hpp \
|
||||
net/dhcp6.hpp \
|
||||
net/dhcp6_client.hpp \
|
||||
net/dhcp6_server.hpp \
|
||||
net/dns_client.hpp \
|
||||
net/dns_headers.hpp \
|
||||
net/icmp6.hpp \
|
||||
net/ip6.hpp \
|
||||
net/ip6_address.hpp \
|
||||
@@ -258,11 +270,8 @@ noinst_HEADERS = \
|
||||
net/ip6_routes.hpp \
|
||||
net/netif.hpp \
|
||||
net/socket.hpp \
|
||||
net/udp6.hpp \
|
||||
net/tcp.hpp \
|
||||
net/dhcp6.hpp \
|
||||
net/dhcp6_client.hpp \
|
||||
net/dhcp6_server.hpp \
|
||||
net/udp6.hpp \
|
||||
thread/address_resolver.hpp \
|
||||
thread/address_resolver_ftd.hpp \
|
||||
thread/address_resolver_mtd.hpp \
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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 the OpenThread UDP API.
|
||||
*/
|
||||
|
||||
#include "openthread/dns.h"
|
||||
|
||||
#include "openthread-instance.h"
|
||||
|
||||
using namespace Thread;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
ThreadError otDnsClientQuery(otInstance *aInstance, const otDnsQuery *aQuery, otDnsResponseHandler aHandler,
|
||||
void *aContext)
|
||||
{
|
||||
return aInstance->mThreadNetif.GetDnsClient().Query(aQuery, aHandler, aContext);
|
||||
}
|
||||
#endif // OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -0,0 +1,517 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <common/debug.hpp>
|
||||
#include <common/code_utils.hpp>
|
||||
#include <net/dns_client.hpp>
|
||||
#include <net/udp6.hpp>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements the DNS client.
|
||||
*/
|
||||
|
||||
using Thread::Encoding::BigEndian::HostSwap16;
|
||||
|
||||
namespace Thread {
|
||||
namespace Dns {
|
||||
|
||||
ThreadError Client::Start(void)
|
||||
{
|
||||
ThreadError error;
|
||||
Ip6::SockAddr addr;
|
||||
|
||||
SuccessOrExit(error = mSocket.Open(&Client::HandleUdpReceive, this));
|
||||
SuccessOrExit(error = mSocket.Bind(addr));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
ThreadError Client::Stop(void)
|
||||
{
|
||||
Message *message = mPendingQueries.GetHead();
|
||||
Message *messageToRemove;
|
||||
QueryMetadata queryMetadata;
|
||||
|
||||
// Remove all pending queries.
|
||||
while (message != NULL)
|
||||
{
|
||||
messageToRemove = message;
|
||||
message = message->GetNext();
|
||||
|
||||
queryMetadata.ReadFrom(*messageToRemove);
|
||||
FinalizeDnsTransaction(*message, queryMetadata, NULL, 0, kThreadError_Abort);
|
||||
}
|
||||
|
||||
return mSocket.Close();
|
||||
}
|
||||
|
||||
ThreadError Client::Query(const otDnsQuery *aQuery, otDnsResponseHandler aHandler, void *aContext)
|
||||
{
|
||||
ThreadError error;
|
||||
QueryMetadata queryMetadata(aHandler, aContext);
|
||||
Message *message = NULL;
|
||||
Message *messageCopy = NULL;
|
||||
Header header;
|
||||
QuestionAaaa question;
|
||||
const Ip6::MessageInfo *messageInfo;
|
||||
|
||||
VerifyOrExit(aQuery->mHostname != NULL && aQuery->mMessageInfo != NULL,
|
||||
error = kThreadError_InvalidArgs);
|
||||
|
||||
header.SetMessageId(mMessageId++);
|
||||
header.SetType(Header::kTypeQuery);
|
||||
header.SetQueryType(Header::kQueryTypeStandard);
|
||||
|
||||
if (!aQuery->mNoRecursion)
|
||||
{
|
||||
header.SetRecursionDesiredFlag();
|
||||
}
|
||||
|
||||
header.SetQuestionCount(1);
|
||||
|
||||
VerifyOrExit((message = NewMessage(header)) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
SuccessOrExit(error = AppendCompressedHostname(*message, aQuery->mHostname));
|
||||
SuccessOrExit(error = question.AppendTo(*message));
|
||||
|
||||
messageInfo = static_cast<const Ip6::MessageInfo *>(aQuery->mMessageInfo);
|
||||
|
||||
queryMetadata.mHostname = aQuery->mHostname;
|
||||
queryMetadata.mTransmissionTime = Timer::GetNow() + kResponseTimeout;
|
||||
queryMetadata.mSourceAddress = messageInfo->GetSockAddr();
|
||||
queryMetadata.mDestinationPort = messageInfo->GetPeerPort();
|
||||
queryMetadata.mDestinationAddress = messageInfo->GetPeerAddr();
|
||||
queryMetadata.mRetransmissionCount = 0;
|
||||
|
||||
VerifyOrExit((messageCopy = CopyAndEnqueueMessage(*message, queryMetadata)) != NULL,
|
||||
error = kThreadError_NoBufs);
|
||||
SuccessOrExit(error = SendMessage(*message, *messageInfo));
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None)
|
||||
{
|
||||
if (message)
|
||||
{
|
||||
message->Free();
|
||||
}
|
||||
|
||||
if (messageCopy)
|
||||
{
|
||||
DequeueMessage(*messageCopy);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
Message *Client::NewMessage(const Header &aHeader)
|
||||
{
|
||||
Message *message = NULL;
|
||||
|
||||
VerifyOrExit((message = mSocket.NewMessage(sizeof(aHeader))) != NULL, ;);
|
||||
message->Prepend(&aHeader, sizeof(aHeader));
|
||||
message->SetOffset(0);
|
||||
|
||||
exit:
|
||||
return message;
|
||||
}
|
||||
|
||||
Message *Client::CopyAndEnqueueMessage(const Message &aMessage, const QueryMetadata &aQueryMetadata)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
uint32_t now = Timer::GetNow();
|
||||
Message *messageCopy = NULL;
|
||||
uint32_t nextTransmissionTime;
|
||||
|
||||
// Create a message copy for further retransmissions.
|
||||
VerifyOrExit((messageCopy = aMessage.Clone()) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
// Append the copy with retransmission data and add it to the queue.
|
||||
SuccessOrExit(error = aQueryMetadata.AppendTo(*messageCopy));
|
||||
mPendingQueries.Enqueue(*messageCopy);
|
||||
|
||||
// Setup the timer.
|
||||
if (mRetransmissionTimer.IsRunning())
|
||||
{
|
||||
// If timer is already running, check if it should be restarted with earlier fire time.
|
||||
nextTransmissionTime = mRetransmissionTimer.Gett0() + mRetransmissionTimer.Getdt();
|
||||
|
||||
if (aQueryMetadata.IsEarlier(nextTransmissionTime))
|
||||
{
|
||||
mRetransmissionTimer.Start(aQueryMetadata.mTransmissionTime - now);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mRetransmissionTimer.Start(aQueryMetadata.mTransmissionTime - now);
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None && messageCopy != NULL)
|
||||
{
|
||||
messageCopy->Free();
|
||||
messageCopy = NULL;
|
||||
}
|
||||
|
||||
return messageCopy;
|
||||
}
|
||||
|
||||
void Client::DequeueMessage(Message &aMessage)
|
||||
{
|
||||
mPendingQueries.Dequeue(aMessage);
|
||||
|
||||
if (mRetransmissionTimer.IsRunning() && (mPendingQueries.GetHead() == NULL))
|
||||
{
|
||||
// No more requests pending, stop the timer.
|
||||
mRetransmissionTimer.Stop();
|
||||
}
|
||||
|
||||
// Free the message memory.
|
||||
aMessage.Free();
|
||||
}
|
||||
|
||||
ThreadError Client::SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
return mSocket.SendTo(aMessage, aMessageInfo);
|
||||
}
|
||||
|
||||
ThreadError Client::SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
ThreadError error;
|
||||
Message *messageCopy = NULL;
|
||||
|
||||
// Create a message copy for lower layers.
|
||||
VerifyOrExit((messageCopy = aMessage.Clone(aMessage.GetLength() - sizeof(QueryMetadata))) != NULL,
|
||||
error = kThreadError_NoBufs);
|
||||
|
||||
// Send the copy.
|
||||
SuccessOrExit(error = SendMessage(*messageCopy, aMessageInfo));
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None && messageCopy != NULL)
|
||||
{
|
||||
messageCopy->Free();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
ThreadError Client::AppendCompressedHostname(Message &aMessage, const char *aHostname)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
uint8_t index = 0;
|
||||
uint8_t labelPosition = 0;
|
||||
uint8_t labelSize = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Look for string separator.
|
||||
if (aHostname[index] == kLabelSeparator || aHostname[index] == kLabelTerminator)
|
||||
{
|
||||
VerifyOrExit(labelSize > 0, error = kThreadError_InvalidArgs);
|
||||
SuccessOrExit(error = aMessage.Append(&labelSize, 1));
|
||||
SuccessOrExit(error = aMessage.Append(&aHostname[labelPosition], labelSize));
|
||||
|
||||
labelPosition += labelSize + 1;
|
||||
labelSize = 0;
|
||||
|
||||
if (aHostname[index] == kLabelTerminator)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
labelSize++;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
// Add termination character at the end.
|
||||
labelSize = kLabelTerminator;
|
||||
SuccessOrExit(error = aMessage.Append(&labelSize, 1));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
ThreadError Client::CompareQuestions(Message &aMessageResponse, Message &aMessageQuery, uint16_t &aOffset)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
uint8_t bufQuery[kBufSize];
|
||||
uint8_t bufResponse[kBufSize];
|
||||
uint16_t read = 0;
|
||||
|
||||
// Compare question section of the query with the response.
|
||||
uint16_t length = aMessageQuery.GetLength() - aMessageQuery.GetOffset() -
|
||||
sizeof(Header) - sizeof(QueryMetadata);
|
||||
uint16_t offset = aMessageQuery.GetOffset() + sizeof(Header);
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
VerifyOrExit((read = aMessageQuery.Read(offset,
|
||||
length < sizeof(bufQuery) ? length : sizeof(bufQuery),
|
||||
bufQuery)) > 0, error = kThreadError_Parse);
|
||||
VerifyOrExit(aMessageResponse.Read(aOffset, read, bufResponse) == read,
|
||||
error = kThreadError_Parse);
|
||||
|
||||
VerifyOrExit(memcmp(bufResponse, bufQuery, read) == 0, error = kThreadError_NotFound);
|
||||
|
||||
aOffset += read;
|
||||
offset += read;
|
||||
length -= read;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
ThreadError Client::SkipHostname(Message &aMessage, uint16_t &aOffset)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
uint8_t buf[kBufSize];
|
||||
uint16_t index;
|
||||
uint16_t read = 0;
|
||||
uint16_t offset = aOffset;
|
||||
uint16_t length = aMessage.GetLength() - aOffset;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
VerifyOrExit((read = aMessage.Read(offset, sizeof(buf), buf)) > 0,
|
||||
error = kThreadError_Parse);
|
||||
|
||||
index = 0;
|
||||
|
||||
while (index < read)
|
||||
{
|
||||
if (buf[index] == kLabelTerminator)
|
||||
{
|
||||
ExitNow(aOffset = offset + 1);
|
||||
}
|
||||
|
||||
if ((buf[index] & kCompressionOffsetMask) == kCompressionOffsetMask)
|
||||
{
|
||||
ExitNow(aOffset = offset + 2);
|
||||
}
|
||||
|
||||
index++;
|
||||
offset++;
|
||||
}
|
||||
|
||||
length -= read;
|
||||
}
|
||||
|
||||
ExitNow(error = kThreadError_Parse);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Message *Client::FindRelatedQuery(const Header &aResponseHeader, QueryMetadata &aQueryMetadata)
|
||||
{
|
||||
uint16_t messageId;
|
||||
Message *message = mPendingQueries.GetHead();
|
||||
|
||||
while (message != NULL)
|
||||
{
|
||||
// Partially read DNS header to obtain message ID only.
|
||||
assert(message->Read(message->GetOffset(), sizeof(messageId), &messageId) == sizeof(messageId));
|
||||
|
||||
if (HostSwap16(messageId) == aResponseHeader.GetMessageId())
|
||||
{
|
||||
aQueryMetadata.ReadFrom(*message);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
message = message->GetNext();
|
||||
}
|
||||
|
||||
exit:
|
||||
return message;
|
||||
}
|
||||
|
||||
void Client::FinalizeDnsTransaction(Message &aQuery, const QueryMetadata &aQueryMetadata,
|
||||
otIp6Address *aAddress, uint32_t aTtl,
|
||||
ThreadError aResult)
|
||||
{
|
||||
DequeueMessage(aQuery);
|
||||
|
||||
if (aQueryMetadata.mResponseHandler != NULL)
|
||||
{
|
||||
aQueryMetadata.mResponseHandler(aQueryMetadata.mResponseContext, aQueryMetadata.mHostname,
|
||||
aAddress, aTtl, aResult);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::HandleRetransmissionTimer(void *aContext)
|
||||
{
|
||||
static_cast<Client *>(aContext)->HandleRetransmissionTimer();
|
||||
}
|
||||
|
||||
void Client::HandleRetransmissionTimer(void)
|
||||
{
|
||||
uint32_t now = Timer::GetNow();
|
||||
uint32_t nextDelta = 0xffffffff;
|
||||
QueryMetadata queryMetadata;
|
||||
Message *message = mPendingQueries.GetHead();
|
||||
Message *nextMessage = NULL;
|
||||
Ip6::MessageInfo messageInfo;
|
||||
|
||||
while (message != NULL)
|
||||
{
|
||||
nextMessage = message->GetNext();
|
||||
queryMetadata.ReadFrom(*message);
|
||||
|
||||
if (queryMetadata.IsLater(now))
|
||||
{
|
||||
// Calculate the next delay and choose the lowest.
|
||||
if (queryMetadata.mTransmissionTime - now < nextDelta)
|
||||
{
|
||||
nextDelta = queryMetadata.mTransmissionTime - now;
|
||||
}
|
||||
}
|
||||
else if (queryMetadata.mRetransmissionCount < kMaxRetransmit)
|
||||
{
|
||||
// Increment retransmission counter and timer.
|
||||
queryMetadata.mRetransmissionCount++;
|
||||
queryMetadata.mTransmissionTime = now + kResponseTimeout;
|
||||
queryMetadata.UpdateIn(*message);
|
||||
|
||||
// Check if retransmission time is lower than current lowest.
|
||||
if (queryMetadata.mTransmissionTime - now < nextDelta)
|
||||
{
|
||||
nextDelta = queryMetadata.mTransmissionTime - now;
|
||||
}
|
||||
|
||||
// Retransmit
|
||||
messageInfo.SetPeerAddr(queryMetadata.mDestinationAddress);
|
||||
messageInfo.SetPeerPort(queryMetadata.mDestinationPort);
|
||||
messageInfo.SetSockAddr(queryMetadata.mSourceAddress);
|
||||
|
||||
SendCopy(*message, messageInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No expected response.
|
||||
FinalizeDnsTransaction(*message, queryMetadata, NULL, 0, kThreadError_ResponseTimeout);
|
||||
}
|
||||
|
||||
message = nextMessage;
|
||||
}
|
||||
|
||||
if (nextDelta != 0xffffffff)
|
||||
{
|
||||
mRetransmissionTimer.Start(nextDelta);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
|
||||
{
|
||||
static_cast<Client *>(aContext)->HandleUdpReceive(*static_cast<Message *>(aMessage),
|
||||
*static_cast<const Ip6::MessageInfo *>(aMessageInfo));
|
||||
}
|
||||
|
||||
void Client::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
Header responseHeader;
|
||||
QueryMetadata queryMetadata;
|
||||
ResourceRecordAaaa record;
|
||||
Message *message = NULL;
|
||||
uint16_t offset;
|
||||
|
||||
// RFC1035 7.3. Resolver cannot rely that a response will come from the same address
|
||||
// which it sent the corresponding query to.
|
||||
(void)aMessageInfo;
|
||||
|
||||
VerifyOrExit(aMessage.Read(aMessage.GetOffset(), sizeof(responseHeader), &responseHeader) ==
|
||||
sizeof(responseHeader), ;);
|
||||
VerifyOrExit(responseHeader.GetType() == Header::kTypeResponse &&
|
||||
responseHeader.GetQuestionCount() == 1 &&
|
||||
responseHeader.IsTruncationFlagSet() == false, ;);
|
||||
|
||||
aMessage.MoveOffset(sizeof(responseHeader));
|
||||
offset = aMessage.GetOffset();
|
||||
|
||||
VerifyOrExit((message = FindRelatedQuery(responseHeader, queryMetadata)) != NULL,);
|
||||
|
||||
if (responseHeader.GetResponseCode() != Header::kResponseSuccess)
|
||||
{
|
||||
ExitNow(error = kThreadError_Failed);
|
||||
}
|
||||
|
||||
// Parse and check the question section.
|
||||
SuccessOrExit(error = CompareQuestions(aMessage, *message, offset));
|
||||
|
||||
// Parse and check the answer section.
|
||||
for (uint32_t index = 0; index < responseHeader.GetAnswerCount(); index++)
|
||||
{
|
||||
SuccessOrExit(error = SkipHostname(aMessage, offset));
|
||||
|
||||
if (offset + sizeof(ResourceRecord) > aMessage.GetLength())
|
||||
{
|
||||
ExitNow(error = kThreadError_Parse);
|
||||
}
|
||||
|
||||
if (aMessage.Read(offset, sizeof(record), &record) != sizeof(record) ||
|
||||
record.GetType() != ResourceRecordAaaa::kType ||
|
||||
record.GetClass() != ResourceRecordAaaa::kClass)
|
||||
{
|
||||
offset += sizeof(ResourceRecord) + record.GetLength();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Return the first found IPv6 address.
|
||||
FinalizeDnsTransaction(*message, queryMetadata, &record.GetAddress(), record.GetTtl(), kThreadError_None);
|
||||
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
ExitNow(error = kThreadError_NotFound);
|
||||
|
||||
exit:
|
||||
|
||||
if (message != NULL && error != kThreadError_None)
|
||||
{
|
||||
FinalizeDnsTransaction(*message, queryMetadata, NULL, 0, error);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace Coap
|
||||
} // namespace Thread
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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.
|
||||
*/
|
||||
|
||||
#ifndef DNS_CLIENT_HPP_
|
||||
#define DNS_CLIENT_HPP_
|
||||
|
||||
#include <openthread/dns.h>
|
||||
#include <openthread/types.h>
|
||||
|
||||
#include <common/message.hpp>
|
||||
#include <common/timer.hpp>
|
||||
#include <net/dns_headers.hpp>
|
||||
#include <net/ip6.hpp>
|
||||
#include <net/netif.hpp>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for the DNS client.
|
||||
*/
|
||||
|
||||
namespace Thread {
|
||||
namespace Dns {
|
||||
|
||||
|
||||
/**
|
||||
* This class implements metadata required for DNS retransmission.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class QueryMetadata
|
||||
{
|
||||
friend class Client;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default constructor for the object.
|
||||
*
|
||||
*/
|
||||
QueryMetadata(void) { memset(this, 0, sizeof(*this)); };
|
||||
|
||||
/**
|
||||
* This constructor initializes the object with specific values.
|
||||
*
|
||||
* @param[in] aHandler Pointer to a handler function for the response.
|
||||
* @param[in] aContext Context for the handler function.
|
||||
*
|
||||
*/
|
||||
QueryMetadata(otDnsResponseHandler aHandler, void *aContext) {
|
||||
memset(this, 0, sizeof(*this));
|
||||
mResponseHandler = aHandler;
|
||||
mResponseContext = aContext;
|
||||
};
|
||||
|
||||
/**
|
||||
* This method appends request data to the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
*
|
||||
* @retval kThreadError_None Successfully appended the bytes.
|
||||
* @retval kThreadError_NoBufs Insufficient available buffers to grow the message.
|
||||
*
|
||||
*/
|
||||
ThreadError AppendTo(Message &aMessage) const {
|
||||
return aMessage.Append(this, sizeof(*this));
|
||||
};
|
||||
|
||||
/**
|
||||
* This method reads request data from the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
*
|
||||
* @returns The number of bytes read.
|
||||
*
|
||||
*/
|
||||
uint16_t ReadFrom(const Message &aMessage) {
|
||||
return aMessage.Read(aMessage.GetLength() - sizeof(*this), sizeof(*this), this);
|
||||
};
|
||||
|
||||
/**
|
||||
* This method updates request data in the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
*
|
||||
* @returns The number of bytes updated.
|
||||
*
|
||||
*/
|
||||
int UpdateIn(Message &aMessage) const {
|
||||
return aMessage.Write(aMessage.GetLength() - sizeof(*this), sizeof(*this), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks if the message shall be sent before the given time.
|
||||
*
|
||||
* @param[in] aTime A time to compare.
|
||||
*
|
||||
* @retval TRUE If the message shall be sent before the given time.
|
||||
* @retval FALSE Otherwise.
|
||||
*/
|
||||
bool IsEarlier(uint32_t aTime) const { return (static_cast<int32_t>(aTime - mTransmissionTime) > 0); };
|
||||
|
||||
/**
|
||||
* This method checks if the message shall be sent after the given time.
|
||||
*
|
||||
* @param[in] aTime A time to compare.
|
||||
*
|
||||
* @retval TRUE If the message shall be sent after the given time.
|
||||
* @retval FALSE Otherwise.
|
||||
*/
|
||||
bool IsLater(uint32_t aTime) const { return (static_cast<int32_t>(aTime - mTransmissionTime) < 0); };
|
||||
|
||||
private:
|
||||
const char *mHostname; ///< A hostname to be find.
|
||||
otDnsResponseHandler mResponseHandler; ///< A function pointer that is called on response reception.
|
||||
void *mResponseContext; ///< A pointer to arbitrary context information.
|
||||
uint32_t mTransmissionTime; ///< Time when the timer should shoot for this message.
|
||||
Ip6::Address mSourceAddress; ///< IPv6 address of the message source.
|
||||
Ip6::Address mDestinationAddress; ///< IPv6 address of the message destination.
|
||||
uint16_t mDestinationPort; ///< UDP port of the message destination.
|
||||
uint8_t mRetransmissionCount; ///< Number of retransmissions.
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements DNS client.
|
||||
*
|
||||
*/
|
||||
class Client
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This constructor initializes the object.
|
||||
*
|
||||
* @param[in] aNetif A reference to the network interface that DNS client should be assigned to.
|
||||
*
|
||||
*/
|
||||
Client(Ip6::Netif &aNetif):
|
||||
mSocket(aNetif.GetIp6().mUdp),
|
||||
mMessageId(0),
|
||||
mRetransmissionTimer(aNetif.GetIp6().mTimerScheduler, &Client::HandleRetransmissionTimer, this) {
|
||||
};
|
||||
|
||||
/**
|
||||
* This method starts the DNS client.
|
||||
*
|
||||
* @retval kThreadError_None Successfully started the DNS client.
|
||||
* @retval kThreadError_Already The socket is already open.
|
||||
*/
|
||||
ThreadError Start(void);
|
||||
|
||||
/**
|
||||
* This method stops the DNS client.
|
||||
*
|
||||
* @retval kThreadError_None Successfully stopped the DNS client.
|
||||
*
|
||||
*/
|
||||
ThreadError Stop(void);
|
||||
|
||||
/**
|
||||
* This method sends a DNS query.
|
||||
*
|
||||
* @param[in] aQuery A pointer to specify DNS query parameters.
|
||||
* @param[in] aHandler A function pointer that shall be called on response reception or time-out.
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
*
|
||||
* @retval kThreadError_None Successfully sent DNS query.
|
||||
* @retval kThreadError_NoBufs Failed to allocate retransmission data.
|
||||
* @retval kThreadError_InvalidArgs Invalid arguments supplied.
|
||||
*
|
||||
*/
|
||||
ThreadError Query(const otDnsQuery *aQuery, otDnsResponseHandler aHandler, void *aContext);
|
||||
|
||||
/**
|
||||
* This method returns a port number used by DNS client.
|
||||
*
|
||||
* @returns A port number.
|
||||
*
|
||||
*/
|
||||
uint16_t GetPort(void) { return mSocket.GetSockName().mPort; };
|
||||
|
||||
private:
|
||||
/**
|
||||
* Retransmission parameters.
|
||||
*
|
||||
*/
|
||||
enum
|
||||
{
|
||||
kResponseTimeout = OPENTHREAD_CONFIG_DNS_RESPONSE_TIMEOUT,
|
||||
kMaxRetransmit = OPENTHREAD_CONFIG_DNS_MAX_RETRANSMIT,
|
||||
};
|
||||
|
||||
/**
|
||||
* Special DNS symbols.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
kLabelTerminator = 0,
|
||||
kLabelSeparator = '.',
|
||||
kCompressionOffsetMask = 0xc0
|
||||
};
|
||||
|
||||
/**
|
||||
* Operating on message buffers.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
kBufSize = 16
|
||||
};
|
||||
|
||||
Message *NewMessage(const Header &aHeader);
|
||||
Message *CopyAndEnqueueMessage(const Message &aMessage, const QueryMetadata &aQueryMetadata);
|
||||
void DequeueMessage(Message &aMessage);
|
||||
ThreadError SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
ThreadError SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
|
||||
ThreadError AppendCompressedHostname(Message &aMessage, const char *aHostname);
|
||||
ThreadError CompareQuestions(Message &aMessageResponse, Message &aMessageQuery, uint16_t &aOffset);
|
||||
ThreadError SkipHostname(Message &aMessage, uint16_t &aOffset);
|
||||
|
||||
Message *FindRelatedQuery(const Header &aResponseHeader, QueryMetadata &aQueryMetadata);
|
||||
void FinalizeDnsTransaction(Message &aQuery, const QueryMetadata &aQueryMetadata,
|
||||
otIp6Address *aAddress, uint32_t aTtl,
|
||||
ThreadError aResult);
|
||||
|
||||
static void HandleRetransmissionTimer(void *aContext);
|
||||
void HandleRetransmissionTimer(void);
|
||||
|
||||
static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
|
||||
void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
|
||||
Ip6::UdpSocket mSocket;
|
||||
|
||||
uint16_t mMessageId;
|
||||
MessageQueue mPendingQueries;
|
||||
Timer mRetransmissionTimer;
|
||||
};
|
||||
|
||||
} // namespace Dns
|
||||
} // namespace Thread
|
||||
|
||||
#endif // DNS_CLIENT_HPP_
|
||||
@@ -0,0 +1,588 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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 includes definitions for generating and processing DNS headers.
|
||||
*/
|
||||
|
||||
#ifndef DNS_HEADER_HPP_
|
||||
#define DNS_HEADER_HPP_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <openthread/types.h>
|
||||
|
||||
#include <common/encoding.hpp>
|
||||
#include <common/message.hpp>
|
||||
|
||||
using Thread::Encoding::BigEndian::HostSwap16;
|
||||
using Thread::Encoding::BigEndian::HostSwap32;
|
||||
|
||||
namespace Thread {
|
||||
|
||||
/**
|
||||
* @namespace Thread::Dns
|
||||
* @brief
|
||||
* This namespace includes definitions for DNS.
|
||||
*
|
||||
*/
|
||||
namespace Dns {
|
||||
|
||||
/**
|
||||
* @addtogroup core-dns
|
||||
*
|
||||
* @brief
|
||||
* This module includes definitions for DNS.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class implements DNS header generation and parsing.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class Header
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default constructor for DNS Header.
|
||||
*
|
||||
*/
|
||||
Header(void) { memset(this, 0, sizeof(*this)); }
|
||||
|
||||
/**
|
||||
* This method returns the Message ID.
|
||||
*
|
||||
* @returns The Message ID value.
|
||||
*
|
||||
*/
|
||||
uint16_t GetMessageId(void) const { return HostSwap16(mMessageId); }
|
||||
|
||||
/**
|
||||
* This method sets the Message ID.
|
||||
*
|
||||
* @param[in] aMessageId The Message ID value.
|
||||
*
|
||||
*/
|
||||
void SetMessageId(uint16_t aMessageId) { mMessageId = HostSwap16(aMessageId); }
|
||||
|
||||
/**
|
||||
* Defines types of DNS message.
|
||||
*
|
||||
*/
|
||||
enum Type
|
||||
{
|
||||
kTypeQuery = 0,
|
||||
kTypeResponse = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* This method returns the type of the message.
|
||||
*
|
||||
* @returns The type of the message.
|
||||
*/
|
||||
Type GetType(void) const { return static_cast<Type>((mFlags[0] & kQrFlagMask) >> kQrFlagOffset); }
|
||||
|
||||
/**
|
||||
* This method sets the type of the message.
|
||||
*
|
||||
* @param[in] aType The type of the message.
|
||||
*
|
||||
*/
|
||||
void SetType(Type aType) {
|
||||
mFlags[0] &= ~kQrFlagMask;
|
||||
mFlags[0] |= static_cast<uint8_t>(aType) << kQrFlagOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines types of query.
|
||||
*
|
||||
*/
|
||||
enum QueryType
|
||||
{
|
||||
kQueryTypeStandard = 0,
|
||||
kQueryTypeInverse = 1,
|
||||
kQueryTypeStatus = 2,
|
||||
kQueryTypeNotify = 4,
|
||||
kQueryTypeUpdate = 5
|
||||
};
|
||||
|
||||
/**
|
||||
* This method returns the type of the query.
|
||||
*
|
||||
* @returns The type of the query.
|
||||
*/
|
||||
QueryType GetQueryType(void) const { return static_cast<QueryType>((mFlags[0] & kOpCodeMask) >> kOpCodeOffset); }
|
||||
|
||||
/**
|
||||
* This method sets the type of the query.
|
||||
*
|
||||
* @param[in] aType The type of the query.
|
||||
*
|
||||
*/
|
||||
void SetQueryType(QueryType aType) {
|
||||
mFlags[0] &= ~kOpCodeMask;
|
||||
mFlags[0] |= static_cast<uint8_t>(aType) << kOpCodeOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method specifies in response message if the responding name server is an
|
||||
* authority for the domain name in question section.
|
||||
*
|
||||
* @returns True if Authoritative Answer flag (AA) is set in the header, false otherwise.
|
||||
*/
|
||||
bool IsAuthoritativeAnswerFlagSet(void) const { return (mFlags[0] & kAaFlagMask) == kAaFlagMask; }
|
||||
|
||||
/**
|
||||
* This method clears the Authoritative Answer flag (AA) in the header.
|
||||
*
|
||||
*/
|
||||
void ClearAuthoritativeAnswerFlag(void) { mFlags[0] &= ~kAaFlagMask; }
|
||||
|
||||
/**
|
||||
* This method sets the Authoritative Answer flag (AA) in the header.
|
||||
*
|
||||
*/
|
||||
void SetAuthoritativeAnswerFlag(void) { mFlags[0] |= kAaFlagMask; }
|
||||
|
||||
/**
|
||||
* This method specifies if message is truncated.
|
||||
*
|
||||
* @returns True if Truncation flag (TC) is set in the header, false otherwise.
|
||||
*/
|
||||
bool IsTruncationFlagSet(void) const { return (mFlags[0] & kTcFlagMask) == kTcFlagMask; }
|
||||
|
||||
/**
|
||||
* This method clears the Truncation flag (TC) in the header.
|
||||
*
|
||||
*/
|
||||
void ClearTruncationFlag(void) { mFlags[0] &= ~kTcFlagMask; }
|
||||
|
||||
/**
|
||||
* This method sets the Truncation flag (TC) in the header.
|
||||
*
|
||||
*/
|
||||
void SetTruncationFlag(void) { mFlags[0] |= kTcFlagMask; }
|
||||
|
||||
/**
|
||||
* This method specifies if resolver wants to direct the name server to pursue
|
||||
* the query recursively.
|
||||
*
|
||||
* @returns True if Recursion Desired flag (RD) is set in the header, false otherwise.
|
||||
*/
|
||||
bool IsRecursionDesiredFlagSet(void) const { return (mFlags[0] & kRdFlagMask) == kRdFlagMask; }
|
||||
|
||||
/**
|
||||
* This method clears the Recursion Desired flag (RD) in the header.
|
||||
*
|
||||
*/
|
||||
void ClearRecursionDesiredFlag(void) { mFlags[0] &= ~kRdFlagMask; }
|
||||
|
||||
/**
|
||||
* This method sets the Recursion Desired flag (RD) in the header.
|
||||
*
|
||||
*/
|
||||
void SetRecursionDesiredFlag(void) { mFlags[0] |= kRdFlagMask; }
|
||||
|
||||
/**
|
||||
* This method denotes whether recursive query support is available in the name server.
|
||||
*
|
||||
* @returns True if Recursion Available flag (RA) is set in the header, false otherwise.
|
||||
*/
|
||||
bool IsRecursionAvailableFlagSet(void) const { return (mFlags[1] & kRaFlagMask) == kRaFlagMask; }
|
||||
|
||||
/**
|
||||
* This method clears the Recursion Available flag (RA) in the header.
|
||||
*
|
||||
*/
|
||||
void ClearRecursionAvailableFlag(void) { mFlags[1] &= ~kRaFlagMask; }
|
||||
|
||||
/**
|
||||
* This method sets the Recursion Available flag (RA) in the header.
|
||||
*
|
||||
*/
|
||||
void SetRecursionAvailableFlag(void) { mFlags[1] |= kRaFlagMask; }
|
||||
|
||||
/**
|
||||
* Defines response codes.
|
||||
*
|
||||
*/
|
||||
enum Response
|
||||
{
|
||||
kResponseSuccess = 0,
|
||||
kResponseFormatError = 1,
|
||||
kResponseServerFailure = 2,
|
||||
kResponseNameError = 3,
|
||||
kResponseNotImplemented = 4,
|
||||
kResponseRefused = 5,
|
||||
kResponseNotAuth = 9,
|
||||
kResponseNotZone = 10,
|
||||
kResponseBadName = 20,
|
||||
kResponseBadAlg = 21,
|
||||
kResponseBadTruncation = 22,
|
||||
};
|
||||
|
||||
/**
|
||||
* This method returns the response code.
|
||||
*
|
||||
* @returns The response code from the header.
|
||||
*/
|
||||
Response GetResponseCode(void) const { return static_cast<Response>((mFlags[1] & kRCodeMask) >> kRCodeOffset); }
|
||||
|
||||
/**
|
||||
* This method sets the response code.
|
||||
*
|
||||
* @param[in] aResponse The type of the response.
|
||||
*
|
||||
*/
|
||||
void SetResponseCode(Response aResponse) {
|
||||
mFlags[1] &= ~kRCodeMask;
|
||||
mFlags[1] |= static_cast<uint8_t>(aResponse) << kRCodeOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the number of entries in question section.
|
||||
*
|
||||
* @returns The number of entries in question section.
|
||||
*
|
||||
*/
|
||||
uint16_t GetQuestionCount(void) const { return HostSwap16(mQdCount); }
|
||||
|
||||
/**
|
||||
* This method sets the number of entries in question section.
|
||||
*
|
||||
* @param[in] aCount The number of entries in question section.
|
||||
*
|
||||
*/
|
||||
void SetQuestionCount(uint16_t aCount) { mQdCount = HostSwap16(aCount); }
|
||||
|
||||
/**
|
||||
* This method returns the number of entries in answer section.
|
||||
*
|
||||
* @returns The number of entries in answer section.
|
||||
*
|
||||
*/
|
||||
uint16_t GetAnswerCount(void) const { return HostSwap16(mAnCount); }
|
||||
|
||||
/**
|
||||
* This method sets the number of entries in answer section.
|
||||
*
|
||||
* @param[in] aCount The number of entries in answer section.
|
||||
*
|
||||
*/
|
||||
void SetAnswerCount(uint16_t aCount) { mAnCount = HostSwap16(aCount); }
|
||||
|
||||
/**
|
||||
* This method returns the number of entries in authority records section.
|
||||
*
|
||||
* @returns The number of entries in authority records section.
|
||||
*
|
||||
*/
|
||||
uint16_t GetAuthorityRecordsCount(void) const { return HostSwap16(mNsCount); }
|
||||
|
||||
/**
|
||||
* This method sets the number of entries in authority records section.
|
||||
*
|
||||
* @param[in] aCount The number of entries in authority records section.
|
||||
*
|
||||
*/
|
||||
void SetAuthorityRecordsCount(uint16_t aCount) { mNsCount = HostSwap16(aCount); }
|
||||
|
||||
/**
|
||||
* This method returns the number of entries in additional records section.
|
||||
*
|
||||
* @returns The number of entries in additional records section.
|
||||
*
|
||||
*/
|
||||
uint16_t GetAdditionalRecordsCount(void) const { return HostSwap16(mArCount); }
|
||||
|
||||
/**
|
||||
* This method sets the number of entries in additional records section.
|
||||
*
|
||||
* @param[in] aCount The number of entries in additional records section.
|
||||
*
|
||||
*/
|
||||
void SetAdditionalRecordsCount(uint16_t aCount) { mArCount = HostSwap16(aCount); }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Protocol Constants (RFC 1035).
|
||||
*
|
||||
*/
|
||||
enum
|
||||
{
|
||||
kQrFlagOffset = 7, ///< QR Flag offset.
|
||||
kQrFlagMask = 0x01 << kQrFlagOffset, ///< QR Flag mask.
|
||||
kOpCodeOffset = 3, ///< OpCode field offset.
|
||||
kOpCodeMask = 0x0f << kOpCodeOffset, ///< OpCode field mask.
|
||||
kAaFlagOffset = 2, ///< AA Flag offset.
|
||||
kAaFlagMask = 0x01 << kAaFlagOffset, ///< AA Flag mask.
|
||||
kTcFlagOffset = 1, ///< TC Flag offset.
|
||||
kTcFlagMask = 0x01 << kTcFlagOffset, ///< TC Flag mask.
|
||||
kRdFlagOffset = 0, ///< RD Flag offset.
|
||||
kRdFlagMask = 0x01 << kRdFlagOffset, ///< RD Flag mask.
|
||||
|
||||
kRaFlagOffset = 7, ///< RA Flag offset.
|
||||
kRaFlagMask = 0x01 << kRaFlagOffset, ///< RA Flag mask.
|
||||
kRCodeOffset = 0, ///< RCODE field offset.
|
||||
kRCodeMask = 0x0f << kRCodeOffset, ///< RCODE field mask.
|
||||
};
|
||||
|
||||
uint16_t mMessageId; ///< A message identifier that is used by the requester to match up replies to outstanding queries.
|
||||
uint8_t mFlags[2]; ///< DNS header flags.
|
||||
uint16_t mQdCount; ///< A number specifying the number of entries in the question section.
|
||||
uint16_t mAnCount; ///< A number specifying the number of entries in the answer section.
|
||||
uint16_t mNsCount; ///< A number specifying the number of entries in the authority records section.
|
||||
uint16_t mArCount; ///< A number specifying the number of entries in the additional records section.
|
||||
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements Resource Record body format (RR).
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class ResourceRecord
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method returns the type of the resource record.
|
||||
*
|
||||
* @returns The type of the resource record.
|
||||
*/
|
||||
uint16_t GetType(void) const { return HostSwap16(mType); }
|
||||
|
||||
/**
|
||||
* This method sets the type of the resource record.
|
||||
*
|
||||
* @param[in] aType The type of the resource record.
|
||||
*
|
||||
*/
|
||||
void SetType(uint16_t aType) { mType = HostSwap16(aType); }
|
||||
|
||||
/**
|
||||
* This method returns the class of the resource record.
|
||||
*
|
||||
* @returns The class of the resource record.
|
||||
*/
|
||||
uint16_t GetClass(void) const { return HostSwap16(mClass); }
|
||||
|
||||
/**
|
||||
* This method sets the class of the resource record.
|
||||
*
|
||||
* @param[in] aClass The class of the resource record.
|
||||
*
|
||||
*/
|
||||
void SetClass(uint16_t aClass) { mClass = HostSwap16(aClass); }
|
||||
|
||||
/**
|
||||
* This method returns the time to live field of the resource record.
|
||||
*
|
||||
* @returns The time to live field of the resource record.
|
||||
*/
|
||||
uint32_t GetTtl(void) const { return HostSwap32(mTtl); }
|
||||
|
||||
/**
|
||||
* This method sets the time to live field of the resource record.
|
||||
*
|
||||
* @param[in] aTtl The time to live field of the resource record.
|
||||
*
|
||||
*/
|
||||
void SetTtl(uint32_t aTtl) { mTtl = HostSwap32(aTtl); }
|
||||
|
||||
/**
|
||||
* This method returns the length of the resource record.
|
||||
*
|
||||
* @returns The length of the resource record.
|
||||
*/
|
||||
uint16_t GetLength(void) const { return HostSwap16(mLength); }
|
||||
|
||||
/**
|
||||
* This method sets the length of the resource record.
|
||||
*
|
||||
* @param[in] aLength The length of the resource record.
|
||||
*
|
||||
*/
|
||||
void SetLength(uint16_t aLength) { mLength = HostSwap16(aLength); }
|
||||
|
||||
private:
|
||||
uint16_t mType; ///< The type of the data in RDATA section.
|
||||
uint16_t mClass; ///< The class of the data in RDATA section.
|
||||
uint32_t mTtl; ///< Specifies the maximum time that the resource record may be cached.
|
||||
uint16_t mLength; ///< The length of RDATA section in bytes.
|
||||
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements Resource Record body format of AAAA type.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class ResourceRecordAaaa: public ResourceRecord
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kType = 0x1C, ///< AAAA Resource Record type.
|
||||
kClass = 0x01, ///< The value of the Internet class.
|
||||
kLength = 16, ///< Size of the AAAA Resource Record type.
|
||||
};
|
||||
|
||||
/**
|
||||
* This method initializes the AAAA Resource Record.
|
||||
*
|
||||
*/
|
||||
void Init(void) {
|
||||
ResourceRecord::SetType(kType);
|
||||
ResourceRecord::SetClass(kClass);
|
||||
ResourceRecord::SetTtl(0);
|
||||
ResourceRecord::SetLength(kLength);
|
||||
memset(&mAddress, 0, sizeof(mAddress));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the IPv6 address of the resource record.
|
||||
*
|
||||
* @param[in] aAddress The IPv6 address of the resource record.
|
||||
*
|
||||
*/
|
||||
void SetAddress(otIp6Address &aAddress) { mAddress = aAddress; }
|
||||
|
||||
/**
|
||||
* This method returns the reference to IPv6 address of the resource record.
|
||||
*
|
||||
* @returns The reference to IPv6 address of the resource record.
|
||||
*/
|
||||
otIp6Address &GetAddress(void) { return mAddress; }
|
||||
|
||||
private:
|
||||
otIp6Address mAddress; ///< Ipv6 Address of AAAA Resource Record.
|
||||
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements Question format.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class Question
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor for Question.
|
||||
*
|
||||
*/
|
||||
Question(uint16_t aType, uint16_t aClass) {
|
||||
SetType(aType);
|
||||
SetClass(aClass);
|
||||
};
|
||||
|
||||
/**
|
||||
* This method returns the type of the question.
|
||||
*
|
||||
* @returns The type of the question.
|
||||
*/
|
||||
uint16_t GetType(void) const { return HostSwap16(mType); }
|
||||
|
||||
/**
|
||||
* This method sets the type of the question.
|
||||
*
|
||||
* @param[in] aType The type of the question.
|
||||
*
|
||||
*/
|
||||
void SetType(uint16_t aType) { mType = HostSwap16(aType); }
|
||||
|
||||
/**
|
||||
* This method returns the class of the question.
|
||||
*
|
||||
* @returns The class of the question.
|
||||
*/
|
||||
uint16_t GetClass(void) const { return HostSwap16(mClass); }
|
||||
|
||||
/**
|
||||
* This method sets the class of the question.
|
||||
*
|
||||
* @param[in] aClass The class of the question.
|
||||
*
|
||||
*/
|
||||
void SetClass(uint16_t aClass) { mClass = HostSwap16(aClass); }
|
||||
|
||||
private:
|
||||
uint16_t mType; ///< The type of the data in question section.
|
||||
uint16_t mClass; ///< The class of the data in question section.
|
||||
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
|
||||
/**
|
||||
* This class implements Question format of AAAA type.
|
||||
*
|
||||
*/
|
||||
class QuestionAaaa: public Question
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kType = 0x1C, ///< AAAA Resource Record type.
|
||||
kClass = 0x01, ///< The value of the Internet class.
|
||||
};
|
||||
|
||||
/**
|
||||
* Default constructor for AAAA Question.
|
||||
*
|
||||
*/
|
||||
QuestionAaaa(void) : Question(kType, kClass) {};
|
||||
|
||||
/**
|
||||
* This method appends request data to the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
*
|
||||
* @retval kThreadError_None Successfully appended the bytes.
|
||||
* @retval kThreadError_NoBufs Insufficient available buffers to grow the message.
|
||||
*
|
||||
*/
|
||||
ThreadError AppendTo(Message &aMessage) const {
|
||||
return aMessage.Append(this, sizeof(*this));
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
} // namespace Dns
|
||||
} // namespace Thread
|
||||
|
||||
#endif // DNS_HEADER_HPP_
|
||||
@@ -321,6 +321,26 @@
|
||||
#define OPENTHREAD_CONFIG_COAP_MAX_RETRANSMIT 4
|
||||
#endif // OPENTHREAD_CONFIG_COAP_MAX_RETRANSMIT
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_DNS_RESPONSE_TIMEOUT
|
||||
*
|
||||
* Maximum time that DNS Client waits for response in milliseconds.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_DNS_RESPONSE_TIMEOUT
|
||||
#define OPENTHREAD_CONFIG_DNS_RESPONSE_TIMEOUT 3000
|
||||
#endif // OPENTHREAD_CONFIG_DNS_RESPONSE_TIMEOUT
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_DNS_MAX_RETRANSMIT
|
||||
*
|
||||
* Maximum number of retransmissions for DNS client.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_DNS_MAX_RETRANSMIT
|
||||
#define OPENTHREAD_CONFIG_DNS_MAX_RETRANSMIT 2
|
||||
#endif // OPENTHREAD_CONFIG_DNS_MAX_RETRANSMIT
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_JOIN_BEACON_VERSION
|
||||
*
|
||||
|
||||
@@ -64,6 +64,9 @@ ThreadNetif::ThreadNetif(Ip6::Ip6 &aIp6):
|
||||
#if OPENTHREAD_ENABLE_DHCP6_SERVER
|
||||
mDhcp6Server(*this),
|
||||
#endif // OPENTHREAD_ENABLE_DHCP6_SERVER
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
mDnsClient(*this),
|
||||
#endif // OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
mActiveDataset(*this),
|
||||
mPendingDataset(*this),
|
||||
mKeyManager(*this),
|
||||
@@ -108,6 +111,9 @@ ThreadError ThreadNetif::Up(void)
|
||||
mCoapClient.Start();
|
||||
#if OPENTHREAD_ENABLE_JOINER
|
||||
mSecureCoapClient.Start();
|
||||
#endif
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
mDnsClient.Start();
|
||||
#endif
|
||||
mMleRouter.Enable();
|
||||
mIsUp = true;
|
||||
@@ -122,6 +128,9 @@ ThreadError ThreadNetif::Down(void)
|
||||
mCoapClient.Stop();
|
||||
#if OPENTHREAD_ENABLE_JOINER
|
||||
mSecureCoapClient.Stop();
|
||||
#endif
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
mDnsClient.Stop();
|
||||
#endif
|
||||
mMleRouter.Disable();
|
||||
mMeshForwarder.Stop();
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include <net/dhcp6.hpp>
|
||||
#include <net/dhcp6_client.hpp>
|
||||
#include <net/dhcp6_server.hpp>
|
||||
#include <net/dns_client.hpp>
|
||||
#include <net/ip6_filter.hpp>
|
||||
#include <net/netif.hpp>
|
||||
#include <thread/address_resolver.hpp>
|
||||
@@ -157,15 +158,15 @@ public:
|
||||
ThreadError RouteLookup(const Ip6::Address &aSource, const Ip6::Address &aDestination, uint8_t *aPrefixMatch);
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the address resolver object.
|
||||
* This method returns a reference to the address resolver object.
|
||||
*
|
||||
* @returns A pointer to the address resolver object.
|
||||
* @returns A reference to the address resolver object.
|
||||
*
|
||||
*/
|
||||
AddressResolver &GetAddressResolver(void) { return mAddressResolver; }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the network diagnostic object.
|
||||
* This method returns a reference to the network diagnostic object.
|
||||
*
|
||||
* @returns A reference to the address resolver object.
|
||||
*
|
||||
@@ -174,7 +175,7 @@ public:
|
||||
|
||||
#if OPENTHREAD_ENABLE_DHCP6_CLIENT
|
||||
/**
|
||||
* This method returns a pointer to the dhcp client object.
|
||||
* This method returns a reference to the dhcp client object.
|
||||
*
|
||||
* @returns A reference to the dhcp client object.
|
||||
*
|
||||
@@ -184,7 +185,7 @@ public:
|
||||
|
||||
#if OPENTHREAD_ENABLE_DHCP6_SERVER
|
||||
/**
|
||||
* This method returns a pointer to the dhcp server object.
|
||||
* This method returns a reference to the dhcp server object.
|
||||
*
|
||||
* @returns A reference to the the dhcp server object.
|
||||
*
|
||||
@@ -192,6 +193,16 @@ public:
|
||||
Dhcp6::Dhcp6Server &GetDhcp6Server(void) { return mDhcp6Server; }
|
||||
#endif // OPENTHREAD_ENABLE_DHCP6_SERVER
|
||||
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
/**
|
||||
* This method returns a reference to the dns client object.
|
||||
*
|
||||
* @returns A reference to the dns client object.
|
||||
*
|
||||
*/
|
||||
Dns::Client &GetDnsClient(void) { return mDnsClient; }
|
||||
#endif // OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
|
||||
/**
|
||||
* This method returns a reference to the CoAP server object.
|
||||
*
|
||||
@@ -217,57 +228,57 @@ public:
|
||||
Ip6::Filter &GetIp6Filter(void) { return mIp6Filter; }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the key manager object.
|
||||
* This method returns a reference to the key manager object.
|
||||
*
|
||||
* @returns A pointer to the key manager object.
|
||||
* @returns A reference to the key manager object.
|
||||
*
|
||||
*/
|
||||
KeyManager &GetKeyManager(void) { return mKeyManager; }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the lowpan object.
|
||||
* This method returns a reference to the lowpan object.
|
||||
*
|
||||
* @returns A pointer to the lowpan object.
|
||||
* @returns A reference to the lowpan object.
|
||||
*
|
||||
*/
|
||||
Lowpan::Lowpan &GetLowpan(void) { return mLowpan; }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the mac object.
|
||||
* This method returns a reference to the mac object.
|
||||
*
|
||||
* @returns A pointer to the mac object.
|
||||
* @returns A reference to the mac object.
|
||||
*
|
||||
*/
|
||||
Mac::Mac &GetMac(void) { return mMac; }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the mle object.
|
||||
* This method returns a reference to the mle object.
|
||||
*
|
||||
* @returns A pointer to the mle object.
|
||||
* @returns A reference to the mle object.
|
||||
*
|
||||
*/
|
||||
Mle::MleRouter &GetMle(void) { return mMleRouter; }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the mesh forwarder object.
|
||||
* This method returns a reference to the mesh forwarder object.
|
||||
*
|
||||
* @returns A pointer to the mesh forwarder object.
|
||||
* @returns A reference to the mesh forwarder object.
|
||||
*
|
||||
*/
|
||||
MeshForwarder &GetMeshForwarder(void) { return mMeshForwarder; }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the network data local object.
|
||||
* This method returns a reference to the network data local object.
|
||||
*
|
||||
* @returns A pointer to the network data local object.
|
||||
* @returns A reference to the network data local object.
|
||||
*
|
||||
*/
|
||||
NetworkData::Local &GetNetworkDataLocal(void) { return mNetworkDataLocal; }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the network data leader object.
|
||||
* This method returns a reference to the network data leader object.
|
||||
*
|
||||
* @returns A pointer to the network data leader object.
|
||||
* @returns A reference to the network data leader object.
|
||||
*
|
||||
*/
|
||||
NetworkData::Leader &GetNetworkDataLeader(void) { return mNetworkDataLeader; }
|
||||
@@ -326,6 +337,9 @@ private:
|
||||
#if OPENTHREAD_ENABLE_DHCP6_SERVER
|
||||
Dhcp6::Dhcp6Server mDhcp6Server;
|
||||
#endif // OPENTHREAD_ENABLE_DHCP6_SERVER
|
||||
#if OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
Dns::Client mDnsClient;
|
||||
#endif // OPENTHREAD_ENABLE_DNS_CLIENT
|
||||
MeshCoP::ActiveDataset mActiveDataset;
|
||||
MeshCoP::PendingDataset mPendingDataset;
|
||||
Ip6::Filter mIp6Filter;
|
||||
|
||||
Reference in New Issue
Block a user