mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 15:47:46 +00:00
[net] add support for DNS Stateful Operations (DSO) (#7081)
This commit adds support for DNS Stateful Operations (DSO) as specified in RFC 8490. It adds `platform/dso_transport.hpp` header file which defines the platform APIs/callbacks for DSO transport layer (e.g., DSN-over-TLS or DNS-over-TCP). The `Dso` module handles establishing connection with a peer, acting either as a DSO client or server, establishing a DSO session over a connection, and then sending and processing DSO request, response, and unidirectional messages (including support for DSO TLV formats). The `Dso` module also manages the session life cycle and timeouts, namely the "Inactivity" and "Keep Alive" timeouts (including sending and processing of Keep Alive messages when needed). It also handles adding encryption padding before sending a message. It implements the padding policy "Random-Block-Length Padding" from RFC 8467. This commit also adds a detailed unit test `test_dso` covering the behavior (including corner cases) of the `Dso` implementation. The unit test provides an implementation of the DSO platform APIs which emulate the DSO transport layer. It also includes a simplified alarm platform implementation (emulating timers and allowing time to advance in the unit test). These allow the unit test to cover more complicated situations and behaviors (timeouts, failures, etc).
This commit is contained in:
@@ -283,6 +283,7 @@ LOCAL_SRC_FILES := \
|
||||
src/core/net/dhcp6_client.cpp \
|
||||
src/core/net/dhcp6_server.cpp \
|
||||
src/core/net/dns_client.cpp \
|
||||
src/core/net/dns_dso.cpp \
|
||||
src/core/net/dns_types.cpp \
|
||||
src/core/net/dnssd_server.cpp \
|
||||
src/core/net/icmp6.cpp \
|
||||
|
||||
@@ -179,6 +179,11 @@ if(OT_DNS_CLIENT)
|
||||
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE=1")
|
||||
endif()
|
||||
|
||||
option(OT_DNS_DSO "enable DNS Stateful Operations (DSO) support")
|
||||
if(OT_DNS_DSO)
|
||||
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_DNS_DSO_ENABLE=1")
|
||||
endif()
|
||||
|
||||
option(OT_DNSSD_SERVER "enable DNS-SD server support")
|
||||
if(OT_DNSSD_SERVER)
|
||||
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE=1")
|
||||
|
||||
@@ -51,6 +51,7 @@ DHCP6_CLIENT ?= 1
|
||||
DHCP6_SERVER ?= 1
|
||||
DIAGNOSTIC ?= 1
|
||||
DNS_CLIENT ?= 1
|
||||
DNS_DSO ?= 1
|
||||
DNSSD_SERVER ?= 1
|
||||
ECDSA ?= 1
|
||||
HISTORY_TRACKER ?= 1
|
||||
|
||||
@@ -32,6 +32,7 @@ This page lists the available common switches with description. Unless stated ot
|
||||
| DEBUG_UART | not implemented | Enables the Debug UART platform feature. |
|
||||
| DEBUG_UART_LOG | not implemented | Enables the log output for the debug UART. Requires OPENTHREAD_CONFIG_ENABLE_DEBUG_UART to be enabled. |
|
||||
| DNS_CLIENT | OT_DNS_CLIENT | Enables support for DNS client. Enable this switch on a device that sends a DNS query for AAAA (IPv6) record. |
|
||||
| DNS_DSO | OT_DNS_DSO | Enables support for DNS Stateful Operations (DSO). |
|
||||
| DNSSD_SERVER | OT_DNSSD_SERVER | Enables support for DNS-SD server. DNS-SD server use service information from local SRP server to resolve DNS-SD query questions. |
|
||||
| DUA | OT_DUA | Enables the Domain Unicast Address feature for Thread 1.2. |
|
||||
| DYNAMIC_LOG_LEVEL | not implemented | Enables the dynamic log level feature. Enable this switch if OpenThread log level is required to be set at runtime. See [Logging guide](https://openthread.io/guides/build/logs) to learn more. |
|
||||
|
||||
@@ -51,6 +51,7 @@ DIAGNOSTIC ?= 0
|
||||
DISABLE_DOC ?= 0
|
||||
DISABLE_TOOLS ?= 0
|
||||
DNS_CLIENT ?= 0
|
||||
DNS_DSO ?= 0
|
||||
DNSSD_SERVER ?= 0
|
||||
DUA ?= 0
|
||||
DYNAMIC_LOG_LEVEL ?= 0
|
||||
@@ -197,6 +198,10 @@ ifeq ($(DNS_CLIENT),1)
|
||||
COMMONCFLAGS += -DOPENTHREAD_CONFIG_DNS_CLIENT_ENABLE=1
|
||||
endif
|
||||
|
||||
ifeq ($(DNS_DSO),1)
|
||||
COMMONCFLAGS += -DOPENTHREAD_CONFIG_DNS_DSO_ENABLE=1
|
||||
endif
|
||||
|
||||
ifeq ($(DNSSD_SERVER),1)
|
||||
COMMONCFLAGS += -DOPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE=1
|
||||
endif
|
||||
|
||||
@@ -61,6 +61,7 @@ add_library(openthread-simulation
|
||||
alarm.c
|
||||
crypto.c
|
||||
diag.c
|
||||
dso_transport.c
|
||||
entropy.c
|
||||
flash.c
|
||||
infra_if.c
|
||||
|
||||
@@ -43,6 +43,7 @@ PLATFORM_SOURCES = \
|
||||
alarm.c \
|
||||
crypto.c \
|
||||
diag.c \
|
||||
dso_transport.c \
|
||||
entropy.c \
|
||||
flash.c \
|
||||
infra_if.c \
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 "platform-simulation.h"
|
||||
|
||||
#include <openthread/platform/dso_transport.h>
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_DSO_ENABLE
|
||||
|
||||
void otPlatDsoEnableListening(otInstance *aInstance, bool aEnable)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aEnable);
|
||||
}
|
||||
|
||||
void otPlatDsoConnect(otPlatDsoConnection *aConnection, const otSockAddr *aPeerSockAddr)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aConnection);
|
||||
OT_UNUSED_VARIABLE(aPeerSockAddr);
|
||||
}
|
||||
|
||||
void otPlatDsoSend(otPlatDsoConnection *aConnection, otMessage *aMessage)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aConnection);
|
||||
OT_UNUSED_VARIABLE(aMessage);
|
||||
}
|
||||
|
||||
void otPlatDsoDisconnect(otPlatDsoConnection *aConnection, otPlatDsoDisconnectMode aMode)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aConnection);
|
||||
OT_UNUSED_VARIABLE(aMode);
|
||||
}
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_DNS_DSO_ENABLE
|
||||
@@ -99,6 +99,7 @@ ot_platform_headers = \
|
||||
openthread/platform/crypto.h \
|
||||
openthread/platform/debug_uart.h \
|
||||
openthread/platform/diag.h \
|
||||
openthread/platform/dso_transport.h \
|
||||
openthread/platform/entropy.h \
|
||||
openthread/platform/flash.h \
|
||||
openthread/platform/infra_if.h \
|
||||
|
||||
@@ -102,6 +102,7 @@ source_set("openthread") {
|
||||
"platform/crypto.h",
|
||||
"platform/debug_uart.h",
|
||||
"platform/diag.h",
|
||||
"platform/dso_transport.h",
|
||||
"platform/entropy.h",
|
||||
"platform/flash.h",
|
||||
"platform/infra_if.h",
|
||||
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (183)
|
||||
#define OPENTHREAD_API_VERSION (184)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 includes the platform abstraction for DNS Stateful Operations (DSO) transport.
|
||||
*/
|
||||
|
||||
#ifndef OPENTHREAD_PLATFORM_DSO_TRANSPORT_H_
|
||||
#define OPENTHREAD_PLATFORM_DSO_TRANSPORT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <openthread/error.h>
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/message.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This structure represents a DSO connection.
|
||||
*
|
||||
* It is an opaque struct (the platform implementation only deals with pointers to this struct).
|
||||
*
|
||||
*/
|
||||
typedef struct otPlatDsoConnection otPlatDsoConnection;
|
||||
|
||||
/**
|
||||
* This function can be used by DSO platform implementation to get the the OpenThread instance associated with a
|
||||
* connection instance.
|
||||
*
|
||||
* @param[in] aConnection A pointer to the DSO connection.
|
||||
*
|
||||
* @returns A pointer to the `otInstance`.
|
||||
*
|
||||
*/
|
||||
extern otInstance *otPlatDsoGetInstance(otPlatDsoConnection *aConnection);
|
||||
|
||||
/**
|
||||
* This function starts or stops listening for incoming connection requests on transport layer.
|
||||
*
|
||||
* For DNS-over-TLS, the transport layer MUST listen on port 853 and follow RFC 7858.
|
||||
*
|
||||
* While listening is enabled, if a connection request is received, the `otPlatDsoAccept()` callback MUST be called.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aEnable TRUE to start listening, FALSE to stop listening.
|
||||
*
|
||||
*/
|
||||
void otPlatDsoEnableListening(otInstance *aInstance, bool aEnable);
|
||||
|
||||
/**
|
||||
* This function is a callback from the DSO platform to indicate an incoming connection request when listening is
|
||||
* enabled.
|
||||
*
|
||||
* This function determines whether or not to accept the connection request. It returns a non-null `otPlatDsoConnection`
|
||||
* pointer if the request is to be accepted, or `NULL` if the request is to be rejected.
|
||||
*
|
||||
* If a non-null connection pointer is returned, the platform layer MUST continue establishing the connection with the
|
||||
* peer. The platform reports the outcome by invoking `otPlatDsoHandleConnected()` callback on success or
|
||||
* `otPlatDsoHandleDisconnected()` callback on failure.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aPeerSockAddr The socket address (IPv6 address and port number) of the peer requesting connection.
|
||||
*
|
||||
* @returns A pointer to the `otPlatDsoConnection` to use if to accept, or `NULL` if to reject.
|
||||
*
|
||||
*/
|
||||
extern otPlatDsoConnection *otPlatDsoAccept(otInstance *aInstance, const otSockAddr *aPeerSockAddr);
|
||||
|
||||
/**
|
||||
* This function requests the platform layer to initiate establishing a connection with a peer.
|
||||
*
|
||||
* The platform reports the outcome by invoking `otPlatDsoHandleConnected()` callback on success or
|
||||
* `otPlatDsoHandleDisconnected()` callback (on failure).
|
||||
*
|
||||
* @param[in] aConnection The connection.
|
||||
* @param[in] aPeerSockAddr The socket address (IPv6 address and port number) of the peer to connect to.
|
||||
*
|
||||
*/
|
||||
void otPlatDsoConnect(otPlatDsoConnection *aConnection, const otSockAddr *aPeerSockAddr);
|
||||
|
||||
/**
|
||||
* This function is a callback from the platform layer to indicate that a connection is successfully established.
|
||||
*
|
||||
* It MUST be called either after accepting an incoming connection (`otPlatDsoAccept`) or after a `otPlatDsoConnect()`
|
||||
* call.
|
||||
*
|
||||
* Only after this callback, the connection can be used to send and receive messages.
|
||||
*
|
||||
* @param[in] aConnection The connection.
|
||||
*
|
||||
*/
|
||||
extern void otPlatDsoHandleConnected(otPlatDsoConnection *aConnection);
|
||||
|
||||
/**
|
||||
* This function sends a DSO message to the peer on a connection.
|
||||
*
|
||||
* This function is used only after the connection is successfully established (after `otPlatDsoHandleConnected()`
|
||||
* callback).
|
||||
*
|
||||
* This function passes the ownership of the @p aMessage to the DSO platform layer, and the platform implementation is
|
||||
* expected to free the message once it is no longer needed.
|
||||
*
|
||||
* The @p aMessage contains the DNS message (starting with DNS header). Note that it does not contain the the length
|
||||
* field that is needed when sending over TLS/TCP transport. The platform layer MUST therefore include the length
|
||||
* field when passing the message to TLS/TCP layer.
|
||||
*
|
||||
* @param[in] aConnection The connection to send on.
|
||||
* @param[in] aMessage The message to send.
|
||||
*
|
||||
*/
|
||||
void otPlatDsoSend(otPlatDsoConnection *aConnection, otMessage *aMessage);
|
||||
|
||||
/**
|
||||
* This function is a callback from the platform layer to indicate that a DNS message was received over a connection.
|
||||
*
|
||||
* The platform MUST call this function only after the connection is successfully established (after callback
|
||||
* `otPlatDsoHandleConnected()` is invoked).
|
||||
*
|
||||
* This function passes the ownership of the @p aMessage from the DSO platform layer to OpenThread. OpenThread will
|
||||
* free the message when no longer needed.
|
||||
*
|
||||
* The @p aMessage MUST contain the DNS message (starting with DNS header) and not include the length field that may
|
||||
* be included in TCP/TLS exchange.
|
||||
*
|
||||
* @param[in] aConnection The connection on which the message was received.
|
||||
* @param[in] aMessage The received message.
|
||||
*
|
||||
*/
|
||||
extern void otPlatDsoHandleReceive(otPlatDsoConnection *aConnection, otMessage *aMessage);
|
||||
|
||||
/**
|
||||
* This enumeration defines disconnect modes.
|
||||
*
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
OT_PLAT_DSO_DISCONNECT_MODE_GRACEFULLY_CLOSE, ///< Gracefully close the connection.
|
||||
OT_PLAT_DSO_DISCONNECT_MODE_FORCIBLY_ABORT, ///< Forcibly abort the connection.
|
||||
} otPlatDsoDisconnectMode;
|
||||
|
||||
/**
|
||||
* This function requests a connection to be disconnected.
|
||||
*
|
||||
* After calling this function, the DSO platform implementation MUST NOT maintain `aConnection` pointer (platform
|
||||
* MUST NOT call any callbacks using this `Connection` pointer anymore). In particular, calling `otPlatDsoDisconnect()`
|
||||
* MUST NOT trigger the callback `otPlatDsoHandleDisconnected()`.
|
||||
*
|
||||
* @param[in] aConnection The connection to disconnect
|
||||
* @param[in] aMode The disconnect mode (close gracefully or forcibly abort).
|
||||
*
|
||||
*/
|
||||
void otPlatDsoDisconnect(otPlatDsoConnection *aConnection, otPlatDsoDisconnectMode aMode);
|
||||
|
||||
/**
|
||||
* This function is a callback from the platform layer to indicate that peer closed/aborted the connection or the
|
||||
* connection establishment failed (e.g., peer rejected a connection request).
|
||||
*
|
||||
* After calling this function, the DSO platform implementation MUST NOT maintain `aConnection` pointer (platform
|
||||
* MUST NOT call any callbacks using this `Connection` pointer anymore).
|
||||
*
|
||||
* @param[in] aConnection The connection which disconnected.
|
||||
* @param[in] aMode The disconnect mode (closed gracefully or forcibly aborted).
|
||||
*
|
||||
*/
|
||||
extern void otPlatDsoHandleDisconnected(otPlatDsoConnection *aConnection, otPlatDsoDisconnectMode aMode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_PLATFORM_DSO_TRANSPORT_H_
|
||||
@@ -51,6 +51,7 @@ readonly OT_BUILD_OPTIONS=(
|
||||
"-DOT_DHCP6_SERVER=ON"
|
||||
"-DOT_DIAGNOSTIC=ON"
|
||||
"-DOT_DNS_CLIENT=ON"
|
||||
"-DOT_DNS_DSO=ON"
|
||||
"-DOT_ECDSA=ON"
|
||||
"-DOT_EXTERNAL_MBEDTLS=external"
|
||||
"-DOT_IP6_FRAGM=ON"
|
||||
|
||||
@@ -54,6 +54,7 @@ build_all_features()
|
||||
"-DOPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_DIAG_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_DNS_CLIENT_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_DNS_DSO_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_ECDSA_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE=1"
|
||||
"-DOPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE=1"
|
||||
|
||||
@@ -96,6 +96,7 @@ readonly OT_CLANG_TIDY_BUILD_OPTS=(
|
||||
'-DOT_DHCP6_SERVER=ON'
|
||||
'-DOT_DIAGNOSTIC=ON'
|
||||
'-DOT_DNS_CLIENT=ON'
|
||||
'-DOT_DNS_DSO=ON'
|
||||
'-DOT_DNSSD_SERVER=ON'
|
||||
'-DOT_DUA=ON'
|
||||
'-DOT_MLR=ON'
|
||||
|
||||
@@ -60,6 +60,7 @@ build_simulation()
|
||||
"-DBUILD_TESTING=ON"
|
||||
"-DOT_ANYCAST_LOCATOR=ON"
|
||||
"-DOT_DNS_CLIENT=ON"
|
||||
"-DOT_DNS_DSO=ON"
|
||||
"-DOT_DNSSD_SERVER=ON"
|
||||
"-DOT_ECDSA=ON"
|
||||
"-DOT_EXTERNAL_HEAP=ON"
|
||||
|
||||
@@ -526,6 +526,8 @@ openthread_core_files = [
|
||||
"net/dhcp6_server.hpp",
|
||||
"net/dns_client.cpp",
|
||||
"net/dns_client.hpp",
|
||||
"net/dns_dso.cpp",
|
||||
"net/dns_dso.hpp",
|
||||
"net/dns_types.cpp",
|
||||
"net/dns_types.hpp",
|
||||
"net/dnssd_server.cpp",
|
||||
@@ -743,6 +745,7 @@ source_set("libopenthread_core_config") {
|
||||
"config/dhcp6_server.h",
|
||||
"config/diag.h",
|
||||
"config/dns_client.h",
|
||||
"config/dns_dso.h",
|
||||
"config/dnssd_server.h",
|
||||
"config/dtls.h",
|
||||
"config/history_tracker.h",
|
||||
|
||||
@@ -156,6 +156,7 @@ set(COMMON_SOURCES
|
||||
net/dhcp6_client.cpp
|
||||
net/dhcp6_server.cpp
|
||||
net/dns_client.cpp
|
||||
net/dns_dso.cpp
|
||||
net/dns_types.cpp
|
||||
net/dnssd_server.cpp
|
||||
net/icmp6.cpp
|
||||
|
||||
@@ -246,6 +246,7 @@ SOURCES_COMMON = \
|
||||
net/dhcp6_client.cpp \
|
||||
net/dhcp6_server.cpp \
|
||||
net/dns_client.cpp \
|
||||
net/dns_dso.cpp \
|
||||
net/dns_types.cpp \
|
||||
net/dnssd_server.cpp \
|
||||
net/icmp6.cpp \
|
||||
@@ -479,6 +480,7 @@ HEADERS_COMMON = \
|
||||
config/dhcp6_server.h \
|
||||
config/diag.h \
|
||||
config/dns_client.h \
|
||||
config/dns_dso.h \
|
||||
config/dnssd_server.h \
|
||||
config/dtls.h \
|
||||
config/history_tracker.h \
|
||||
@@ -543,6 +545,7 @@ HEADERS_COMMON = \
|
||||
net/dhcp6_client.hpp \
|
||||
net/dhcp6_server.hpp \
|
||||
net/dns_client.hpp \
|
||||
net/dns_dso.hpp \
|
||||
net/dns_types.hpp \
|
||||
net/dnssd_server.hpp \
|
||||
net/icmp6.hpp \
|
||||
|
||||
@@ -746,6 +746,13 @@ template <> inline Dns::ServiceDiscovery::Server &Instance::Get(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_DSO_ENABLE
|
||||
template <> inline Dns::Dso &Instance::Get(void)
|
||||
{
|
||||
return mThreadNetif.mDnsDso;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_TMF_NETWORK_DIAG_MTD_ENABLE
|
||||
template <> inline NetworkDiagnostic::NetworkDiagnostic &Instance::Get(void)
|
||||
{
|
||||
|
||||
@@ -240,18 +240,22 @@ public:
|
||||
/**
|
||||
* This static method converts a given number of seconds to milliseconds.
|
||||
*
|
||||
* @param[in] aSeconds The seconds value to convert to milliseconds.
|
||||
*
|
||||
* @returns The number of milliseconds.
|
||||
*
|
||||
*/
|
||||
static uint32_t SecToMsec(uint32_t aSeconds) { return aSeconds * 1000u; }
|
||||
static uint32_t constexpr SecToMsec(uint32_t aSeconds) { return aSeconds * 1000u; }
|
||||
|
||||
/**
|
||||
* This static method converts a given number of milliseconds to seconds.
|
||||
*
|
||||
* @param[in] aMilliseconds The milliseconds value to convert to seconds.
|
||||
*
|
||||
* @returns The number of seconds.
|
||||
*
|
||||
*/
|
||||
static uint32_t MsecToSec(uint32_t aMilliseconds) { return aMilliseconds / 1000u; }
|
||||
static uint32_t constexpr MsecToSec(uint32_t aMilliseconds) { return aMilliseconds / 1000u; }
|
||||
|
||||
private:
|
||||
static constexpr uint32_t kDistantFuture = (1UL << 31);
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 compile-time configurations for the DNS Stateful Operations (DSO).
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_DNS_DSO_H_
|
||||
#define CONFIG_DNS_DSO_H_
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_DNS_DSO_ENABLE
|
||||
*
|
||||
* Define to 1 to enable DSO support.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_DNS_DSO_ENABLE
|
||||
#define OPENTHREAD_CONFIG_DNS_DSO_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_DNS_DSO_CONNECTING_TIMEOUT
|
||||
*
|
||||
* Specifies the maximum time (in msec) waiting for a connection to be established by DSO platform layer.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_DNS_DSO_CONNECTING_TIMEOUT
|
||||
#define OPENTHREAD_CONFIG_DNS_DSO_CONNECTING_TIMEOUT (45 * 1000)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_DNS_DSO_RESPONSE_TIMEOUT
|
||||
*
|
||||
* Specifies the maximum time (in msec) waiting for a response to a request.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_DNS_DSO_RESPONSE_TIMEOUT
|
||||
#define OPENTHREAD_CONFIG_DNS_DSO_RESPONSE_TIMEOUT (30 * 1000)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_DNS_DSO_MAX_PENDING_REQUESTS
|
||||
*
|
||||
* Specifies the maximum number of pending requests per DSO session.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_DNS_DSO_MAX_PENDING_REQUESTS
|
||||
#define OPENTHREAD_CONFIG_DNS_DSO_MAX_PENDING_REQUESTS 3
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_DNS_DSO_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,973 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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_DSO_HPP_
|
||||
#define DNS_DSO_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_DSO_ENABLE
|
||||
|
||||
#include <openthread/platform/dso_transport.h>
|
||||
|
||||
#include "common/array.hpp"
|
||||
#include "common/as_core_type.hpp"
|
||||
#include "common/const_cast.hpp"
|
||||
#include "common/encoding.hpp"
|
||||
#include "common/linked_list.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "common/message.hpp"
|
||||
#include "common/non_copyable.hpp"
|
||||
#include "common/timer.hpp"
|
||||
#include "net/dns_types.hpp"
|
||||
#include "net/socket.hpp"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for the DNS Stateful Operations (DSO) per RFC-8490.
|
||||
*/
|
||||
|
||||
struct otPlatDsoConnection
|
||||
{
|
||||
};
|
||||
|
||||
namespace ot {
|
||||
namespace Dns {
|
||||
|
||||
using ot::Encoding::BigEndian::HostSwap16;
|
||||
using ot::Encoding::BigEndian::HostSwap32;
|
||||
|
||||
extern "C" otPlatDsoConnection *otPlatDsoAccept(otInstance *aInstance, const otSockAddr *aPeerSockAddr);
|
||||
|
||||
extern "C" void otPlatDsoHandleConnected(otPlatDsoConnection *aConnection);
|
||||
extern "C" void otPlatDsoHandleReceive(otPlatDsoConnection *aConnection, otMessage *aMessage);
|
||||
extern "C" void otPlatDsoHandleDisconnected(otPlatDsoConnection *aConnection, otPlatDsoDisconnectMode aMode);
|
||||
|
||||
/**
|
||||
* This class implements DNS Stateful Operations (DSO).
|
||||
*
|
||||
*/
|
||||
class Dso : public InstanceLocator, private NonCopyable
|
||||
{
|
||||
friend otPlatDsoConnection *otPlatDsoAccept(otInstance *aInstance, const otSockAddr *aPeerSockAddr);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Infinite Keep Alive or Inactivity timeout value.
|
||||
*
|
||||
* This value can be used for either Keep Alive or Inactivity timeout interval. It practically disables the
|
||||
* timeout.
|
||||
*
|
||||
*/
|
||||
static constexpr uint32_t kInfiniteTimeout = 0xffffffff;
|
||||
|
||||
/**
|
||||
* Default Keep Alive or Inactivity timeout value (in msec).
|
||||
*
|
||||
* On a new DSO session, if no explicit DSO Keep Alive message exchange has taken place, the default value for both
|
||||
* timeouts is 15 seconds [RFC 8490 - 6.2].
|
||||
*
|
||||
*/
|
||||
static constexpr uint32_t kDefaultTimeout = TimeMilli::SecToMsec(15);
|
||||
|
||||
/**
|
||||
* The minimum allowed Keep Alive interval (in msec).
|
||||
*
|
||||
* Any value less than ten seconds is invalid [RFC 8490 - 6.5.2].
|
||||
*
|
||||
*/
|
||||
static constexpr uint32_t kMinKeepAliveInterval = TimeMilli::SecToMsec(10);
|
||||
|
||||
/**
|
||||
* The maximum wait time for a DSO response to a DSO request (in msec).
|
||||
*
|
||||
*/
|
||||
static constexpr uint32_t kResponseTimeout = OPENTHREAD_CONFIG_DNS_DSO_RESPONSE_TIMEOUT;
|
||||
|
||||
/**
|
||||
* The maximum wait time for a connection to be established (in msec).
|
||||
*
|
||||
*/
|
||||
static constexpr uint32_t kConnectingTimeout = OPENTHREAD_CONFIG_DNS_DSO_CONNECTING_TIMEOUT;
|
||||
|
||||
/**
|
||||
* The minimum Inactivity wait time on a server before closing a connection.
|
||||
*
|
||||
* A server will abort an idle session after five seconds or twice the inactivity timeout value, whichever is
|
||||
* greater [RFC 8490 - 6.4.1].
|
||||
*
|
||||
*/
|
||||
static constexpr uint32_t kMinServerInactivityWaitTime = TimeMilli::SecToMsec(5);
|
||||
|
||||
/**
|
||||
* This class represents a DSO TLV.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class Tlv
|
||||
{
|
||||
public:
|
||||
typedef uint16_t Type; ///< DSO TLV type.
|
||||
|
||||
static constexpr Type kReservedType = 0; ///< Reserved TLV type.
|
||||
static constexpr Type kKeepAliveType = 1; ///< Keep Alive TLV type.
|
||||
static constexpr Type kRetryDelayType = 2; ///< Retry Delay TLV type.
|
||||
static constexpr Type kEncryptionPaddingType = 3; ///< Encryption Padding TLV type.
|
||||
|
||||
/**
|
||||
* This method initializes the `Tlv` instance with a given type and length.
|
||||
*
|
||||
* @param[in] aType The TLV type.
|
||||
* @param[in] aLength The TLV length.
|
||||
*
|
||||
*/
|
||||
void Init(Type aType, uint16_t aLength)
|
||||
{
|
||||
mType = HostSwap16(aType);
|
||||
mLength = HostSwap16(aLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the TLV type.
|
||||
*
|
||||
* @returns The TLV type.
|
||||
*
|
||||
*/
|
||||
Type GetType(void) const { return HostSwap16(mType); }
|
||||
|
||||
/**
|
||||
* This method gets the TLV length.
|
||||
*
|
||||
* @returns The TLV length (in bytes).
|
||||
*
|
||||
*/
|
||||
uint16_t GetLength(void) const { return HostSwap16(mLength); }
|
||||
|
||||
/**
|
||||
* This method returns the total size of the TLV (including the type and length fields).
|
||||
*
|
||||
* @returns The total size (number of bytes) of the TLV.
|
||||
*
|
||||
*/
|
||||
uint32_t GetSize(void) const { return sizeof(Tlv) + static_cast<uint32_t>(GetLength()); }
|
||||
|
||||
private:
|
||||
Type mType;
|
||||
uint16_t mLength;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class represents a DSO connection to a peer.
|
||||
*
|
||||
*/
|
||||
class Connection : public otPlatDsoConnection,
|
||||
public InstanceLocator,
|
||||
public LinkedListEntry<Connection>,
|
||||
private NonCopyable
|
||||
{
|
||||
friend class Dso;
|
||||
friend class LinkedList<Connection>;
|
||||
friend class LinkedListEntry<Connection>;
|
||||
friend void otPlatDsoHandleConnected(otPlatDsoConnection *aConnection);
|
||||
friend void otPlatDsoHandleReceive(otPlatDsoConnection *aConnection, otMessage *aMessage);
|
||||
friend void otPlatDsoHandleDisconnected(otPlatDsoConnection *aConnection, otPlatDsoDisconnectMode aMode);
|
||||
|
||||
public:
|
||||
typedef uint16_t MessageId; ///< This type represents a DSO Message Identifier.
|
||||
|
||||
/**
|
||||
* This enumeration defines the `Connection` states.
|
||||
*
|
||||
*/
|
||||
enum State : uint8_t
|
||||
{
|
||||
kStateDisconnected, ///< Disconnected.
|
||||
kStateConnecting, ///< Connecting to peer.
|
||||
kStateConnectedButSessionless, ///< Connected but DSO session is not yet established.
|
||||
kStateEstablishingSession, ///< Establishing DSO session.
|
||||
kStateSessionEstablished, ///< DSO session is established.
|
||||
};
|
||||
|
||||
/**
|
||||
* This enumeration defines the disconnect modes.
|
||||
*
|
||||
*/
|
||||
enum DisconnectMode : uint8_t
|
||||
{
|
||||
kGracefullyClose = OT_PLAT_DSO_DISCONNECT_MODE_GRACEFULLY_CLOSE, ///< Close the connection gracefully.
|
||||
kForciblyAbort = OT_PLAT_DSO_DISCONNECT_MODE_FORCIBLY_ABORT, ///< Forcibly abort the connection.
|
||||
};
|
||||
|
||||
/**
|
||||
* This enumeration defines the disconnect reason.
|
||||
*
|
||||
*/
|
||||
enum DisconnectReason : uint8_t
|
||||
{
|
||||
kReasonFailedToConnect, ///< Failed to connect (e.g., peer did not accept or timed out).
|
||||
kReasonResponseTimeout, ///< Response timeout (no response from peer after `kResponseTimeout`).
|
||||
kReasonPeerDoesNotSupportDso, ///< Peer does not support DSO.
|
||||
kReasonPeerClosed, ///< Peer closed the connection gracefully.
|
||||
kReasonPeerAborted, ///< Peer forcibly aborted the connection.
|
||||
kReasonInactivityTimeout, ///< Connection closed or aborted due to Inactivity timeout.
|
||||
kReasonKeepAliveTimeout, ///< Connection closed due to Keep Alive timeout.
|
||||
kReasonServerRetryDelayRequest, ///< Connection closed due to server requesting retry delay.
|
||||
kReasonPeerMisbehavior, ///< Aborted due to peer misbehavior (fatal error).
|
||||
kReasonUnknown, ///< Unknown reason.
|
||||
};
|
||||
|
||||
/**
|
||||
* This class defines the callback functions used by a `Connection`.
|
||||
*
|
||||
*/
|
||||
class Callbacks
|
||||
{
|
||||
friend class Connection;
|
||||
|
||||
public:
|
||||
/**
|
||||
* This callback signals that the connection is established (entering `kStateConnectedButSessionless`).
|
||||
*
|
||||
* On a client, this callback can be used to send the first DSO request to start establishing the session.
|
||||
*
|
||||
* @param[in] aConnection A reference to the connection.
|
||||
*
|
||||
*/
|
||||
typedef void (&HandleConnected)(Connection &aConnection);
|
||||
|
||||
/**
|
||||
* This callback signals that the DSO session is established (entering `kStateSessionEstablished`).
|
||||
*
|
||||
* @param[in] aConnection A reference to the connection.
|
||||
*
|
||||
*/
|
||||
typedef void (&HandleSessionEstablished)(Connection &aConnection);
|
||||
|
||||
/**
|
||||
* This callback signals that the DSO session is disconnected by DSO module or the peer.
|
||||
*
|
||||
* After this callback is invoked the DSO module will no longer track the related `Connection` instance. It
|
||||
* can be reclaimed by the caller, e.g., freed if it was heap allocated.
|
||||
*
|
||||
* The `Connection::GetDisconnectReason()` can be used the get the disconnect reason.
|
||||
*
|
||||
* @param[in] aConnection A reference to the connection.
|
||||
*
|
||||
*/
|
||||
typedef void (&HandleDisconnected)(Connection &aConnection);
|
||||
|
||||
/**
|
||||
* This callback requests processing of a received DSO request message.
|
||||
*
|
||||
* If the processing is successful a response can be sent using `Connection::SendResponseMessage()` method.
|
||||
*
|
||||
* Note that @p aMessage is a `const` so the ownership of the message is not passed in this callback.
|
||||
* The message will be freed by the `Connection` after returning from this callback, so if it needs to be
|
||||
* persisted the callback implementation needs to create its own copy.
|
||||
*
|
||||
* The offset in @p aMessage is set to point to the start of the DSO TLVs. DSO module only reads and
|
||||
* validates the first TLV (primary TLV) from the message. It is up to the callback implementation to parse
|
||||
* and validate the rest of the TLVs in the message.
|
||||
*
|
||||
* @param[in] aConnection A reference to the connection.
|
||||
* @param[in] aMessageId The message ID of the received request.
|
||||
* @param[in] aMessage The received message. Message offset is set to the start of the TLVs.
|
||||
* @param[in] aPrimaryTlvType The primary TLV type.
|
||||
*
|
||||
* @retval kErrorSuccess The request message was processed successfully.
|
||||
* @retval kErrorNotFound The @p aPrimaryTlvType is not known (not supported). This error triggers a DNS
|
||||
* response with error code 11 "DSO TLV TYPE not implemented" to be sent.
|
||||
* @retval kErrorAbort Fatal error (misbehavior by peer). This triggers aborting of the connection.
|
||||
*
|
||||
*/
|
||||
typedef Error (&ProcessRequestMessage)(Connection & aConnection,
|
||||
MessageId aMessageId,
|
||||
const Message &aMessage,
|
||||
Tlv::Type aPrimaryTlvType);
|
||||
|
||||
/**
|
||||
* This callback requests processing of a received DSO unidirectional message.
|
||||
*
|
||||
* Similar to `ProcessRequestMessage()` the ownership of @p aMessage is not passed in this callback.
|
||||
*
|
||||
* The offset in @p aMessage is set to point to the start of the DSO TLVs. DSO module only reads and
|
||||
* validates the first TLV (primary TLV) from the message. It is up to the callback implementation to parse
|
||||
* and validate the rest of the TLVs in the message.
|
||||
*
|
||||
* @param[in] aConnection A reference to the connection.
|
||||
* @param[in] aMessage The received message. Message offset is set to the start of the TLVs.
|
||||
* @param[in] aPrimaryTlvType The primary TLV type.
|
||||
*
|
||||
* @retval kErrorSuccess The unidirectional message was processed successfully.
|
||||
* @retval kErrorAbort Fatal error (misbehavior by peer). This triggers aborting of the connection. If
|
||||
* @p aPrimaryTlvType is not known in a unidirectional message, it is a fatal error.
|
||||
*
|
||||
*/
|
||||
typedef Error (&ProcessUnidirectionalMessage)(Connection & aConnection,
|
||||
const Message &aMessage,
|
||||
Tlv::Type aPrimaryTlvType);
|
||||
|
||||
/**
|
||||
* This callback requests processing of a received DSO response message.
|
||||
*
|
||||
* Before invoking this callback, the `Connection` implementation already verifies that:
|
||||
*
|
||||
* (1) this response is for a pending previously sent request (based on the message ID),
|
||||
* (2) if no error response code in DNS @p aHeader and the response contains a response primary TLV, the
|
||||
* the response primary TLV matches the request primary TLV.
|
||||
*
|
||||
* Similar to `ProcessRequestMessage()` the ownership of @p aMessage is not passed in this callback.
|
||||
*
|
||||
* The offset in @p aMessage is set to point to the start of the DSO TLVs. DSO module only reads and
|
||||
* validates the first TLV (primary TLV) from the message. It is up to the callback implementation to parse
|
||||
* and validate the rest of the TLVs in the message.
|
||||
*
|
||||
* @param[in] aConnection A reference to the connection.
|
||||
* @param[in] aHeader The DNS header of the received response.
|
||||
* @param[in] aMessage The received message. Message offset is set to the start of the TLVs.
|
||||
* @param[in] aResponseTlvType The primary TLV type in the response message, or `Tlv::kReservedType` if
|
||||
* the response contains no TLV.
|
||||
* @param[in] aRequestTlvType The primary TLV type of the corresponding request message.
|
||||
*
|
||||
* @retval kErrorSuccess The message was processed successfully.
|
||||
* @retval kErrorAbort Fatal error (misbehavior by peer). This triggers aborting of the connection.
|
||||
*
|
||||
*/
|
||||
typedef Error (&ProcessResponseMessage)(Connection & aConnection,
|
||||
const Dns::Header &aHeader,
|
||||
const Message & aMessage,
|
||||
Tlv::Type aResponseTlvType,
|
||||
Tlv::Type aRequestTlvType);
|
||||
/**
|
||||
* This constructor initializes a `Callbacks` object setting all the callback functions.
|
||||
*
|
||||
* @param[in] aHandleConnected The `HandleConnected` callback.
|
||||
* @param[in] aHandleSessionEstablished The `HandleSessionEstablished` callback.
|
||||
* @param[in] aHandleDisconnected The `HandleDisconnected` callback.
|
||||
* @param[in] aProcessRequestMessage The `ProcessRequestMessage` callback.
|
||||
* @param[in] aProcessUnidirectionalMessage The `ProcessUnidirectionalMessage` callback.
|
||||
* @param[in] aProcessResponseMessage The `ProcessResponseMessage` callback.
|
||||
*
|
||||
*/
|
||||
Callbacks(HandleConnected aHandleConnected,
|
||||
HandleSessionEstablished aHandleSessionEstablished,
|
||||
HandleDisconnected aHandleDisconnected,
|
||||
ProcessRequestMessage aProcessRequestMessage,
|
||||
ProcessUnidirectionalMessage aProcessUnidirectionalMessage,
|
||||
ProcessResponseMessage aProcessResponseMessage)
|
||||
: mHandleConnected(aHandleConnected)
|
||||
, mHandleSessionEstablished(aHandleSessionEstablished)
|
||||
, mHandleDisconnected(aHandleDisconnected)
|
||||
, mProcessRequestMessage(aProcessRequestMessage)
|
||||
, mProcessUnidirectionalMessage(aProcessUnidirectionalMessage)
|
||||
, mProcessResponseMessage(aProcessResponseMessage)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
HandleConnected mHandleConnected;
|
||||
HandleSessionEstablished mHandleSessionEstablished;
|
||||
HandleDisconnected mHandleDisconnected;
|
||||
ProcessRequestMessage mProcessRequestMessage;
|
||||
ProcessUnidirectionalMessage mProcessUnidirectionalMessage;
|
||||
ProcessResponseMessage mProcessResponseMessage;
|
||||
};
|
||||
|
||||
/**
|
||||
* This constructor initializes a `Connection` instance.
|
||||
*
|
||||
* The `kDefaultTimeout` will be used for @p aInactivityTimeout and @p aKeepAliveInterval. The
|
||||
* @p aKeepAliveInterval MUST NOT be less than `kMinKeepAliveInterval`.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aPeerSockAddr The peer socket address.
|
||||
* @param[in] aCallbacks A reference to the `Callbacks` instance used by the `Connection`.
|
||||
* @param[in] aInactivityTimeout The Inactivity timeout interval (in msec).
|
||||
* @param[in] aKeepAliveInterval The Keep Alive timeout interval (in msec).
|
||||
*
|
||||
*/
|
||||
Connection(Instance & aInstance,
|
||||
const Ip6::SockAddr &aPeerSockAddr,
|
||||
Callbacks & aCallbacks,
|
||||
uint32_t aInactivityTimeout = kDefaultTimeout,
|
||||
uint32_t aKeepAliveInterval = kDefaultTimeout);
|
||||
|
||||
/**
|
||||
* This method gets the current state of the `Connection`.
|
||||
*
|
||||
* @returns The `Connection` state.
|
||||
*
|
||||
*/
|
||||
State GetState(void) const { return mState; }
|
||||
|
||||
/**
|
||||
* This method returns the `Connection` peer socket address.
|
||||
*
|
||||
* @returns The peer socket address.
|
||||
*
|
||||
*/
|
||||
const Ip6::SockAddr &GetPeerSockAddr(void) const { return mPeerSockAddr; }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device is acting as a DSO server on this `Connection`.
|
||||
*
|
||||
* Server is the software entity with a listening socket, awaiting incoming connection requests.
|
||||
*
|
||||
* @retval TRUE Device is acting as a server on this connection.
|
||||
* @retval FALSE Device is acting as a client on this connection.
|
||||
*
|
||||
*/
|
||||
bool IsServer(void) const { return mIsServer; }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the device is acting as a DSO client on this `Connection`.
|
||||
*
|
||||
* Client is the software entity that initiates a connection to the server's listening socket.
|
||||
*
|
||||
* @retval TRUE Device is acting as a client on this connection.
|
||||
* @retval FALSE Device is acting as a server on this connection.
|
||||
*
|
||||
*/
|
||||
bool IsClient(void) const { return !mIsServer; }
|
||||
|
||||
/**
|
||||
* This method allocates a new DSO message.
|
||||
*
|
||||
* @returns A pointer to the allocated message or `nullptr` if out of message buffers.
|
||||
*
|
||||
*/
|
||||
Message *NewMessage(void);
|
||||
|
||||
/**
|
||||
* This method requests the device to initiate a connection (connect as a client) to the peer (acting as a
|
||||
* server).
|
||||
*
|
||||
* This method MUST be called when `Connection` is `kStateDisconnected` state.
|
||||
*
|
||||
* After calling `Connect()`, either
|
||||
* - `Callbacks::HandleConnected()` is invoked when connection is successfully established, or
|
||||
* - `Callbacks::HandleDisconnected()` is invoked if the connection cannot be established (e.g., peer does not
|
||||
* accept it or we time out waiting for it). The disconnect reason is set to `kReasonFailedToConnect`.
|
||||
*
|
||||
* Calling `Connect()` passes the control and ownership of the `Connection` instance to the DSO module (which
|
||||
* adds the `Connection` into a list of client connections - see `Dso::FindClientConnection()`). The ownership
|
||||
* is passed back to the caller when the `Connection` gets disconnected, i.e., when either
|
||||
* - the user requests a disconnect by an explicit call to `Disconnect()` method, or,
|
||||
* - when `HandleDisconnected()` callback is invoked (after its is closed by DSO module itself or by peer).
|
||||
*
|
||||
*/
|
||||
void Connect(void);
|
||||
|
||||
/**
|
||||
* This method requests the connection to be disconnected.
|
||||
*
|
||||
* Note that calling `Disconnect()` does not trigger the `Callbacks::HandleDisconnected()` to be invoked (as
|
||||
* this callback is used when DSO module itself or the peer disconnects the connections).
|
||||
*
|
||||
* After the call to `Disconnect()` the caller can take back ownership of the `Connection` (e.g., can free the
|
||||
* `Connection` instance if it was heap allocated).
|
||||
*
|
||||
* @param[in] aMode Determines whether to close the connection gracefully or forcibly abort the connection.
|
||||
* @param[in] aReason The disconnect reason.
|
||||
*
|
||||
*/
|
||||
void Disconnect(DisconnectMode aMode, DisconnectReason aReason);
|
||||
|
||||
/**
|
||||
* This method returns the last disconnect reason.
|
||||
*
|
||||
* @returns The last disconnect reason.
|
||||
*
|
||||
*/
|
||||
DisconnectReason GetDisconnectReason(void) const { return mDisconnectReason; }
|
||||
|
||||
/**
|
||||
* This method implicitly marks the DSO session as established (set state to `kStateSessionEstablished`).
|
||||
*
|
||||
* This method MUST be called when `Connection is in `kStateConnectedButSessionless` state.
|
||||
*
|
||||
* The DSO module itself will mark the session as established after the first successful DSO message exchange
|
||||
* (sending a request message from client and receiving a response from server).
|
||||
*
|
||||
* This method is intended for implicit DSO session establishment where it may be known in advance by some
|
||||
* external means that both client and server support DSO and then the session may be established as soon as
|
||||
* the connection is established.
|
||||
*
|
||||
*/
|
||||
void MarkSessionEstablished(void);
|
||||
|
||||
/**
|
||||
* This method sends a DSO request message.
|
||||
*
|
||||
* This method MUST be called when `Connection` is in certain states depending on whether it is acting as a
|
||||
* client or server:
|
||||
* - On client, a request message can be sent after connection is established (`kStateConnectedButSessionless`).
|
||||
* The first request is used to establish the DSO session. While in `kStateEstablishingSession` or
|
||||
* `kStateSessionEstablished` other DSO request messages can be sent to the server.
|
||||
* - On server, a request can be sent only after DSO session is established (`kStateSessionEstablished`).
|
||||
*
|
||||
* The prepared message needs to contain the DSO TLVs. The DNS header will be added by the DSO module itself.
|
||||
* Also there is no need to append the "Encryption Padding TLV" to the message as it will be added by the DSO
|
||||
* module before sending the message to the transport layer.
|
||||
*
|
||||
* On success (when this method returns `kErrorNone`) it takes the ownership of the @p aMessage. On failure the
|
||||
* caller still owns the message and may need to free it.
|
||||
*
|
||||
* @param[in] aMessage The DSO request message to send.
|
||||
* @param[out] aMessageId A reference to output the message ID used for the transmission (may be used by
|
||||
* the caller to track the response from `Callbacks::ProcessResponseMessage()`).
|
||||
* @param[in] aResponseTimeout The response timeout in msec (default value is `kResponseTimeout`)
|
||||
*
|
||||
* @retval kErrorNone Successfully sent the DSO request message and updated @p aMessageId.
|
||||
* @retval kErrorNoBufs Failed to allocate new buffer to prepare the message (append header or padding).
|
||||
*
|
||||
*/
|
||||
Error SendRequestMessage(Message & aMessage,
|
||||
MessageId &aMessageId,
|
||||
uint32_t aResponseTimeout = kResponseTimeout);
|
||||
|
||||
/**
|
||||
* This method sends a DSO unidirectional message.
|
||||
*
|
||||
* This method MUST be called when session is established (in `kStateSessionEstablished` state).
|
||||
*
|
||||
* Similar to `SendRequestMessage()` method, only TLV(s) need to be included in the message. The DNS header and
|
||||
* Encryption Padding TLV will be added by the DSO module.
|
||||
*
|
||||
* On success (when this method returns `kErrorNone`) it takes the ownership of the @p aMessage. On failure the
|
||||
* caller still owns the message and may need to free it.
|
||||
*
|
||||
* @param[in] aMessage The DSO unidirectional message to send.
|
||||
*
|
||||
* @retval kErrorNone Successfully sent the DSO message.
|
||||
* @retval kErrorNoBufs Failed to allocate new buffer to prepare the message (append header or padding).
|
||||
*
|
||||
*/
|
||||
Error SendUnidirectionalMessage(Message &aMessage);
|
||||
|
||||
/**
|
||||
* This method sends a DSO response message for a received request message.
|
||||
*
|
||||
* Similar to `SendRequestMessage()` method, only TLV(s) need to be included in the message. The DNS header and
|
||||
* Encryption Padding TLV will be added by DSO module.
|
||||
*
|
||||
* On success (when this method returns `kErrorNone`) it takes the ownership of the @p aMessage. On failure the
|
||||
* caller still owns the message and may need to free it.
|
||||
*
|
||||
* @param[in] aMessage The DSO response message to send.
|
||||
* @param[in] aResponseId The message ID to use for the response.
|
||||
*
|
||||
* @retval kErrorNone Successfully sent the DSO response message.
|
||||
* @retval kErrorNoBufs Failed to allocate new buffer to prepare the message (append header or padding).
|
||||
*
|
||||
*/
|
||||
Error SendResponseMessage(Message &aMessage, MessageId aResponseId);
|
||||
|
||||
/**
|
||||
* This method returns the Keep Alive timeout interval (in msec).
|
||||
*
|
||||
* On client, this indicates the value granted by server, on server the value to grant.
|
||||
*
|
||||
* @returns The keep alive timeout interval (in msec).
|
||||
*
|
||||
*/
|
||||
uint32_t GetKeepAliveInterval(void) const { return mKeepAlive.GetInterval(); }
|
||||
|
||||
/**
|
||||
* This method returns the Inactivity timeout interval (in msec).
|
||||
*
|
||||
* On client, this indicates the value granted by server, on server the value to grant.
|
||||
*
|
||||
* @returns The inactivity timeout interval (in msec).
|
||||
*
|
||||
*/
|
||||
uint32_t GetInactivityTimeout(void) const { return mInactivity.GetInterval(); }
|
||||
|
||||
/**
|
||||
* This method sends a Keep Alive message.
|
||||
*
|
||||
* This method MUST be called when `Connection` is in certain states depending on whether it is acting as a
|
||||
* client or server:
|
||||
* - On client, it can be called in any state after the connection is established. Sending Keep Alive message
|
||||
* can be used to initiate establishing DSO session.
|
||||
* - On server, it can be used only after session is established (`kStateSessionEstablished`).
|
||||
*
|
||||
* On a client, the Keep Alive message is sent as a request message. On server it is sent as a unidirectional
|
||||
* message.
|
||||
*
|
||||
* @retval kErrorNone Successfully prepared and sent a Keep Alive message.
|
||||
* @retval kErrorNoBufs Failed to allocate message to send.
|
||||
*
|
||||
*/
|
||||
Error SendKeepAliveMessage(void);
|
||||
|
||||
/**
|
||||
* This method sets the Inactivity and Keep Alive timeout intervals.
|
||||
*
|
||||
* On client, the specified timeout intervals are used in Keep Alive request message, i.e., they are the values
|
||||
* that client would wish to get. On server, the given timeout intervals specify the values that server would
|
||||
* grant to a client upon receiving a Keep Alive request from it.
|
||||
*
|
||||
* This method can be called in any `Connection` state. If current state allows, calling this method will also
|
||||
* trigger sending of a Keep Alive message (as if `SendKeepAliveMessage()` is also called). For states which
|
||||
* trigger the tx, see `SendKeepAliveMessage()`.
|
||||
*
|
||||
* The special value `kInfiniteTimeout` can be used for either Inactivity or Keep Alive interval which disables
|
||||
* the corresponding timer. The Keep Alive interval should be larger than or equal to minimum
|
||||
* `kMinKeepAliveInterval`, otherwise `kErrorInvalidArgs` is returned.
|
||||
*
|
||||
* @param[in] aInactivityTimeout The Inactivity timeout (in msec).
|
||||
* @param[in] aKeepAliveTimeout The Keep Alive timeout (in msec).
|
||||
*
|
||||
* @retval kErrorNone Successfully set the timeouts and sent a Keep Alive message.
|
||||
* @retval kErrorInvalidArgs The given timeouts are not valid.
|
||||
* @retval kErrorNoBufs Failed to allocate message to send.
|
||||
*
|
||||
*/
|
||||
Error SetTimeouts(uint32_t aInactivityTimeout, uint32_t aKeepAliveInterval);
|
||||
|
||||
/**
|
||||
* This method enables/disables long-lived operation on the session.
|
||||
*
|
||||
* When a long-lived operation is active, the Inactivity timeout is always cleared, i.e., the DSO session stays
|
||||
* connected even if no messages are exchanged.
|
||||
*
|
||||
* @param[in] aLongLivedOperation A boolean indicating whether or not a long-lived operation is active.
|
||||
*
|
||||
*/
|
||||
void SetLongLivedOperation(bool aLongLivedOperation);
|
||||
|
||||
/**
|
||||
* This method sends a unidirectional Retry Delay message from server to client.
|
||||
*
|
||||
* This method MUST be used on a server only and when DSO session is already established, i.e., in state
|
||||
* `kStateSessionEstablished`. It sends a unidirectional Retry Delay message to client requesting it to close
|
||||
* the connection and not connect again for at least the specified delay amount.
|
||||
*
|
||||
* Note that calling `SendRetryDelayMessage()` does not by itself close the connection on server side. It is
|
||||
* up to the user of the DSO module to implement a wait time delay before deciding to close/abort the connection
|
||||
* from server side, in case the client does not close it upon receiving the Retry Delay message.
|
||||
*
|
||||
* @param[in] aDelay The retry delay interval (in msec).
|
||||
* @param[in] aResponseCode The DNS RCODE to include in the Retry Delay message.
|
||||
*
|
||||
* @retval kErrorNone Successfully prepared and sent a Retry Delay message to client.
|
||||
* @retval kErrorNoBufs Failed to allocate message to send.
|
||||
*
|
||||
*/
|
||||
Error SendRetryDelayMessage(uint32_t aDelay,
|
||||
Dns::Header::Response aResponseCode = Dns::Header::kResponseSuccess);
|
||||
|
||||
/**
|
||||
* This method returns the requested retry delay interval (in msec) by server.
|
||||
*
|
||||
* This method MUST be used after a `HandleDisconnected()` callback with `kReasonServerRetryDelayRequest`
|
||||
*
|
||||
* @returns The retry delay interval requested by server.
|
||||
*
|
||||
*/
|
||||
uint32_t GetRetryDelay(void) const { return mRetryDelay; }
|
||||
|
||||
/**
|
||||
* This method returns the DNS error code in the last retry delay message received on client from server.
|
||||
*
|
||||
* This method MUST be used after a `HandleDisconnected()` callback with `kReasonServerRetryDelayRequest`
|
||||
*
|
||||
* @returns The DNS error code in the last Retry Delay message received on client from server.
|
||||
*
|
||||
*/
|
||||
Dns::Header::Response GetRetryDelayErrorCode(void) const { return mRetryDelayErrorCode; }
|
||||
|
||||
private:
|
||||
enum MessageType : uint8_t
|
||||
{
|
||||
kRequestMessage,
|
||||
kResponseMessage,
|
||||
kUnidirectionalMessage,
|
||||
};
|
||||
|
||||
// Info about pending request messages (message ID, primary TLV type, and response timeout).
|
||||
class PendingRequests
|
||||
{
|
||||
public:
|
||||
static constexpr uint8_t kMaxPendingRequests = OPENTHREAD_CONFIG_DNS_DSO_MAX_PENDING_REQUESTS;
|
||||
|
||||
void Clear(void) { mRequests.Clear(); }
|
||||
bool IsEmpty(void) const { return mRequests.IsEmpty(); }
|
||||
bool Contains(MessageId aMessageId, Tlv::Type &aPrimaryTlvType) const;
|
||||
Error Add(MessageId aMessageId, Tlv::Type aPrimaryTlvType, TimeMilli aResponseTimeout);
|
||||
void Remove(MessageId aMessageId);
|
||||
bool HasAnyTimedOut(TimeMilli aNow) const;
|
||||
TimeMilli GetNextFireTime(TimeMilli aNow) const;
|
||||
|
||||
private:
|
||||
struct Entry
|
||||
{
|
||||
bool Matches(MessageId aMessageId) const { return mMessageId == aMessageId; }
|
||||
|
||||
MessageId mMessageId;
|
||||
Tlv::Type mPrimaryTlvType;
|
||||
TimeMilli mTimeout; // Latest time by which a response is expected.
|
||||
};
|
||||
|
||||
Array<Entry, kMaxPendingRequests> mRequests;
|
||||
};
|
||||
|
||||
// Inactivity or KeepAlive timeout
|
||||
class Timeout
|
||||
{
|
||||
public:
|
||||
static constexpr uint32_t kInfinite = kInfiniteTimeout;
|
||||
static constexpr uint32_t kDefault = kDefaultTimeout;
|
||||
|
||||
explicit Timeout(uint32_t aInterval)
|
||||
: mInterval(aInterval)
|
||||
, mRequest(aInterval)
|
||||
{
|
||||
}
|
||||
|
||||
// On client, timeout value granted by server. On server, value to grant.
|
||||
uint32_t GetInterval(void) const { return mInterval; }
|
||||
void SetInterval(uint32_t aInterval) { mInterval = LimitInterval(aInterval); }
|
||||
|
||||
// On client, timeout value to request. Not used on server.
|
||||
uint32_t GetRequestInterval(void) const { return mRequest; }
|
||||
void SetRequestInterval(uint32_t aInterval) { mRequest = LimitInterval(aInterval); }
|
||||
|
||||
TimeMilli GetExpirationTime(void) const { return mExpirationTime; }
|
||||
void SetExpirationTime(TimeMilli aTime) { mExpirationTime = aTime; }
|
||||
|
||||
bool IsUsed(void) const { return (mInterval != kInfinite); }
|
||||
bool IsExpired(TimeMilli aNow) const { return (mExpirationTime <= aNow); }
|
||||
|
||||
private:
|
||||
static constexpr uint32_t kMaxInterval = TimerMilli::kMaxDelay / 2;
|
||||
|
||||
uint32_t LimitInterval(uint32_t aInterval) const
|
||||
{
|
||||
// If it is not infinite, limit the interval to `kMaxInterval`.
|
||||
// The max limit ensures that even twice the interval is less
|
||||
// than max OpenThread timer duration.
|
||||
return (aInterval == kInfinite) ? aInterval : OT_MIN(aInterval, kMaxInterval);
|
||||
}
|
||||
|
||||
uint32_t mInterval;
|
||||
uint32_t mRequest;
|
||||
TimeMilli mExpirationTime;
|
||||
};
|
||||
|
||||
void Init(bool aIsServer);
|
||||
void SetState(State aState);
|
||||
void SignalAnyStateChange(void);
|
||||
void Accept(void);
|
||||
void MarkAsConnecting(void);
|
||||
void HandleConnected(void);
|
||||
void HandleDisconnected(DisconnectMode aMode);
|
||||
void MarkAsDisconnected(void);
|
||||
|
||||
Error SendKeepAliveMessage(MessageType aMessageType, MessageId aResponseId);
|
||||
Error SendMessage(Message & aMessage,
|
||||
MessageType aMessageType,
|
||||
MessageId & aMessageId,
|
||||
Dns::Header::Response aResponseCode = Dns::Header::kResponseSuccess,
|
||||
uint32_t aResponseTimeout = kResponseTimeout);
|
||||
void HandleReceive(Message &aMessage);
|
||||
Error ReadPrimaryTlv(const Message &aMessage, Tlv::Type &aPrimaryTlvType) const;
|
||||
Error ProcessRequestOrUnidirectionalMessage(const Dns::Header &aHeader,
|
||||
const Message & aMessage,
|
||||
Tlv::Type aPrimaryTlvType);
|
||||
Error ProcessResponseMessage(const Dns::Header &aHeader, const Message &aMessage, Tlv::Type aPrimaryTlvType);
|
||||
Error ProcessKeepAliveMessage(const Dns::Header &aHeader, const Message &aMessage);
|
||||
Error ProcessRetryDelayMessage(const Dns::Header &aHeader, const Message &aMessage);
|
||||
void SendErrorResponse(const Dns::Header &aHeader, Dns::Header::Response aResponseCode);
|
||||
Error AppendPadding(Message &aMessage);
|
||||
|
||||
void AdjustInactivityTimeout(uint32_t aNewTimeout);
|
||||
uint32_t CalculateServerInactivityWaitTime(void) const;
|
||||
void ResetTimeouts(bool aIsKeepAliveMessage);
|
||||
TimeMilli GetNextFireTime(TimeMilli aNow) const;
|
||||
void HandleTimer(TimeMilli aNow, TimeMilli &aNextTime);
|
||||
|
||||
bool Matches(const Ip6::SockAddr &aPeerSockAddr) const { return mPeerSockAddr == aPeerSockAddr; }
|
||||
|
||||
static const char *StateToString(State aState);
|
||||
static const char *MessageTypeToString(MessageType aMessageType);
|
||||
static const char *DisconnectReasonToString(DisconnectReason aReason);
|
||||
|
||||
Connection * mNext;
|
||||
Callbacks & mCallbacks;
|
||||
Ip6::SockAddr mPeerSockAddr;
|
||||
State mState;
|
||||
MessageId mNextMessageId;
|
||||
PendingRequests mPendingRequests;
|
||||
bool mIsServer : 1;
|
||||
bool mStateDidChange : 1;
|
||||
bool mLongLivedOperation : 1;
|
||||
Timeout mInactivity;
|
||||
Timeout mKeepAlive;
|
||||
uint32_t mRetryDelay;
|
||||
Dns::Header::Response mRetryDelayErrorCode;
|
||||
DisconnectReason mDisconnectReason;
|
||||
};
|
||||
|
||||
/**
|
||||
* This callback function is used by DSO module to determine whether or not to accept a connection request from a
|
||||
* peer.
|
||||
*
|
||||
* The function MUST return a non-null `Connection` pointer if the request is to be accepted. The returned
|
||||
* `Connection` instance MUST be in `kStateDisconnected`. The DSO module will take the ownership of the `Connection`
|
||||
* instance (adds it into a list of server connections - see `FindServerConnection()`). The ownership is passed
|
||||
* back to the caller when the `Connection` gets disconnected, i.e., when either the user requests a disconnect by
|
||||
* an explicit call to the method `Connection::Disconnect()`, or, if `HandleDisconnected()` callback is invoked
|
||||
* (after connection is closed by the DSO module itself or by the peer).
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in] aPeerSockAddr The peer socket address.
|
||||
*
|
||||
* @returns A pointer to the `Connection` to use if to accept, or `nullptr` if to reject the connection request.
|
||||
*
|
||||
*/
|
||||
typedef Connection *(*AcceptHandler)(Instance &aInstance, const Ip6::SockAddr &aPeerSockAddr);
|
||||
|
||||
/**
|
||||
* This constructor initializes the `Dso` module.
|
||||
*
|
||||
*/
|
||||
explicit Dso(Instance &aInstance);
|
||||
|
||||
/**
|
||||
* This method starts listening for DSO connection requests from peers.
|
||||
*
|
||||
* Once a connection request (from a peer) is received, the `Dso` module will invoke the `AcceptHandler` to
|
||||
* determine whether to accept or reject the request.
|
||||
*
|
||||
* @param[in] aAcceptHandler Accept handler callback.
|
||||
*
|
||||
*/
|
||||
void StartListening(AcceptHandler aAcceptHandler);
|
||||
|
||||
/**
|
||||
* This method stops listening for DSO connection requests from peers.
|
||||
*
|
||||
*/
|
||||
void StopListening(void);
|
||||
|
||||
/**
|
||||
* This method finds a client `Connection` instance (being currently managed by the `Dso` module) matching a given
|
||||
* peer socket address.
|
||||
*
|
||||
* @param[in] aPeerSockAddr The peer socket address.
|
||||
*
|
||||
* @returns A pointer to the matching `Connection` or `nullptr` if no match is found.
|
||||
*
|
||||
*/
|
||||
Connection *FindClientConnection(const Ip6::SockAddr &aPeerSockAddr);
|
||||
|
||||
/**
|
||||
* This method finds a server `Connection` instance (being currently managed by the `Dso` module) matching a given
|
||||
* peer socket address.
|
||||
*
|
||||
* @param[in] aPeerSockAddr The peer socket address.
|
||||
*
|
||||
* @returns A pointer to the matching `Connection` or `nullptr` if no match is found.
|
||||
*
|
||||
*/
|
||||
Connection *FindServerConnection(const Ip6::SockAddr &aPeerSockAddr);
|
||||
|
||||
private:
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class KeepAliveTlv : public Tlv
|
||||
{
|
||||
public:
|
||||
static constexpr Type kType = kKeepAliveType;
|
||||
|
||||
void Init(void) { Tlv::Init(kType, sizeof(*this) - sizeof(Tlv)); }
|
||||
|
||||
bool IsValid(void) const { return GetSize() >= sizeof(*this); }
|
||||
|
||||
uint32_t GetInactivityTimeout(void) const { return HostSwap32(mInactivityTimeout); }
|
||||
void SetInactivityTimeout(uint32_t aTimeout) { mInactivityTimeout = HostSwap32(aTimeout); }
|
||||
|
||||
uint32_t GetKeepAliveInterval(void) const { return HostSwap32(mKeepAliveInterval); }
|
||||
void SetKeepAliveInterval(uint32_t aInterval) { mKeepAliveInterval = HostSwap32(aInterval); }
|
||||
|
||||
private:
|
||||
uint32_t mInactivityTimeout; // In msec
|
||||
uint32_t mKeepAliveInterval; // In msec
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class RetryDelayTlv : public Tlv
|
||||
{
|
||||
public:
|
||||
static constexpr Type kType = kRetryDelayType;
|
||||
|
||||
void Init(void) { Tlv::Init(kType, sizeof(*this) - sizeof(Tlv)); }
|
||||
|
||||
bool IsValid(void) const { return GetSize() >= sizeof(*this); }
|
||||
|
||||
uint32_t GetRetryDelay(void) const { return HostSwap32(mRetryDelay); }
|
||||
void SetRetryDelay(uint32_t aDelay) { mRetryDelay = HostSwap32(aDelay); }
|
||||
|
||||
private:
|
||||
uint32_t mRetryDelay;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class EncryptionPaddingTlv : public Tlv
|
||||
{
|
||||
public:
|
||||
static constexpr Type kType = kEncryptionPaddingType;
|
||||
|
||||
void Init(uint16_t aPaddingLength) { Tlv::Init(kType, aPaddingLength); }
|
||||
|
||||
private:
|
||||
// Value is padding bytes (zero) based on the length.
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
Connection *AcceptConnection(const Ip6::SockAddr &aPeerSockAddr);
|
||||
|
||||
static void HandleTimer(Timer &aTimer);
|
||||
void HandleTimer(void);
|
||||
|
||||
AcceptHandler mAcceptHandler;
|
||||
LinkedList<Connection> mClientConnections;
|
||||
LinkedList<Connection> mServerConnections;
|
||||
TimerMilli mTimer;
|
||||
};
|
||||
|
||||
} // namespace Dns
|
||||
|
||||
DefineCoreType(otPlatDsoConnection, Dns::Dso::Connection);
|
||||
DefineMapEnum(otPlatDsoDisconnectMode, Dns::Dso::Connection::DisconnectMode);
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_DNS_DSO_ENABLE
|
||||
|
||||
#endif // DNS_DSO_HPP_
|
||||
@@ -77,6 +77,7 @@ Error Header::ResponseCodeToError(Response aResponse)
|
||||
break;
|
||||
|
||||
case kResponseNotImplemented: // Server does not support the query type (OpCode).
|
||||
case kDsoTypeNotImplemented: // DSO TLV type is not implemented.
|
||||
error = kErrorNotImplemented;
|
||||
break;
|
||||
|
||||
|
||||
@@ -151,7 +151,8 @@ public:
|
||||
kQueryTypeInverse = 1,
|
||||
kQueryTypeStatus = 2,
|
||||
kQueryTypeNotify = 4,
|
||||
kQueryTypeUpdate = 5
|
||||
kQueryTypeUpdate = 5,
|
||||
kQueryTypeDso = 6,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -273,6 +274,7 @@ public:
|
||||
kResponseRecordNotExists = 8, ///< Some RRset that ought to exist, does not exist.
|
||||
kResponseNotAuth = 9, ///< Service is not authoritative for zone.
|
||||
kResponseNotZone = 10, ///< A name is not in the zone.
|
||||
kDsoTypeNotImplemented = 11, ///< DSO TLV TYPE is not implemented.
|
||||
kResponseBadName = 20, ///< Bad name.
|
||||
kResponseBadAlg = 21, ///< Bad algorithm.
|
||||
kResponseBadTruncation = 22, ///< Bad truncation.
|
||||
@@ -312,6 +314,7 @@ public:
|
||||
* - kResponseRecordNotExists (8) : Some RRset that ought to exist, does not exist -> kErrorNotFound
|
||||
* - kResponseNotAuth (9) : Service is not authoritative for zone -> kErrorSecurity
|
||||
* - kResponseNotZone (10) : A name is not in the zone -> kErrorParse
|
||||
* - kDsoTypeNotImplemented (11) : DSO TLV Type is not implemented -> kErrorNotImplemented
|
||||
* - kResponseBadName (20) : Bad name -> kErrorParse
|
||||
* - kResponseBadAlg (21) : Bad algorithm -> kErrorSecurity
|
||||
* - kResponseBadTruncation (22) : Bad truncation -> kErrorParse
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
#include "config/dhcp6_server.h"
|
||||
#include "config/diag.h"
|
||||
#include "config/dns_client.h"
|
||||
#include "config/dns_dso.h"
|
||||
#include "config/dnssd_server.h"
|
||||
#include "config/dtls.h"
|
||||
#include "config/history_tracker.h"
|
||||
|
||||
@@ -74,6 +74,9 @@ ThreadNetif::ThreadNetif(Instance &aInstance)
|
||||
#if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
|
||||
, mDnssdServer(aInstance)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_DNS_DSO_ENABLE
|
||||
, mDnsDso(aInstance)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
|
||||
, mSntpClient(aInstance)
|
||||
#endif
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "net/dhcp6_client.hpp"
|
||||
#include "net/dhcp6_server.hpp"
|
||||
#include "net/dns_client.hpp"
|
||||
#include "net/dns_dso.hpp"
|
||||
#include "net/dnssd_server.hpp"
|
||||
#include "net/ip6_filter.hpp"
|
||||
#include "net/nd_agent.hpp"
|
||||
@@ -190,6 +191,9 @@ private:
|
||||
#if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
|
||||
Dns::ServiceDiscovery::Server mDnssdServer;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_DNS_DSO_ENABLE
|
||||
Dns::Dso mDnsDso;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_SNTP_CLIENT_ENABLE
|
||||
Sntp::Client mSntpClient;
|
||||
#endif
|
||||
|
||||
@@ -67,4 +67,12 @@
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_LOG_OUTPUT OPENTHREAD_CONFIG_LOG_OUTPUT_APP
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_DNS_DSO_ENABLE
|
||||
*
|
||||
* Define to 1 to enable DSO support.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_DNS_DSO_ENABLE 1
|
||||
|
||||
#endif /* OPENTHREAD_CORE_TORANJ_CONFIG_SIMULATION_H_ */
|
||||
|
||||
@@ -255,6 +255,28 @@ target_link_libraries(ot-test-dns
|
||||
|
||||
add_test(NAME ot-test-dns COMMAND ot-test-dns)
|
||||
|
||||
add_executable(ot-test-dso
|
||||
test_dso.cpp
|
||||
)
|
||||
|
||||
target_include_directories(ot-test-dso
|
||||
PRIVATE
|
||||
${COMMON_INCLUDES}
|
||||
)
|
||||
|
||||
target_compile_options(ot-test-dso
|
||||
PRIVATE
|
||||
${COMMON_COMPILE_OPTIONS}
|
||||
)
|
||||
|
||||
target_link_libraries(ot-test-dso
|
||||
PRIVATE
|
||||
${COMMON_LIBS}
|
||||
)
|
||||
|
||||
add_test(NAME ot-test-dso COMMAND ot-test-dso)
|
||||
|
||||
|
||||
add_executable(ot-test-ecdsa
|
||||
test_ecdsa.cpp
|
||||
)
|
||||
|
||||
@@ -117,6 +117,7 @@ check_PROGRAMS += \
|
||||
ot-test-cmd-line-parser \
|
||||
ot-test-data \
|
||||
ot-test-dns \
|
||||
ot-test-dso \
|
||||
ot-test-ecdsa \
|
||||
ot-test-flash \
|
||||
ot-test-heap \
|
||||
@@ -209,6 +210,9 @@ ot_test_data_SOURCES = $(COMMON_SOURCES) test_data.cpp
|
||||
ot_test_dns_LDADD = $(COMMON_LDADD)
|
||||
ot_test_dns_SOURCES = $(COMMON_SOURCES) test_dns.cpp
|
||||
|
||||
ot_test_dso_LDADD = $(COMMON_LDADD)
|
||||
ot_test_dso_SOURCES = $(COMMON_SOURCES) test_dso.cpp
|
||||
|
||||
ot_test_ecdsa_LDADD = $(COMMON_LDADD)
|
||||
ot_test_ecdsa_SOURCES = $(COMMON_SOURCES) test_ecdsa.cpp
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -557,4 +557,33 @@ otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aTh
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_DSO_ENABLE
|
||||
|
||||
OT_TOOL_WEAK void otPlatDsoEnableListening(otInstance *aInstance, bool aEnable)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aEnable);
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK void otPlatDsoConnect(otPlatDsoConnection *aConnection, const otSockAddr *aPeerSockAddr)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aConnection);
|
||||
OT_UNUSED_VARIABLE(aPeerSockAddr);
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK void otPlatDsoSend(otPlatDsoConnection *aConnection, otMessage *aMessage)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aConnection);
|
||||
OT_UNUSED_VARIABLE(aMessage);
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK void otPlatDsoDisconnect(otPlatDsoConnection *aConnection, otPlatDsoDisconnectMode aMode)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aConnection);
|
||||
OT_UNUSED_VARIABLE(aMode);
|
||||
}
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_DNS_DSO_ENABLE
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include <openthread/config.h>
|
||||
#include <openthread/platform/alarm-milli.h>
|
||||
#include <openthread/platform/dso_transport.h>
|
||||
#include <openthread/platform/entropy.h>
|
||||
#include <openthread/platform/logging.h>
|
||||
#include <openthread/platform/misc.h>
|
||||
|
||||
Reference in New Issue
Block a user