[dnssd-server] implement DNS-SD discovery proxy functionality in core (#10050)

This commit implements a generic discovery proxy in the DNS-SD server.
It uses a set of newly added `otPlatDnssd` platform DNS-SD(mDNS) APIs
to start or stop browsers, SRV/TXT resolvers, and IPv6/IPv4 address
resolvers. These APIs closely match the native OpenThread mDNS
implementation.

OpenThread DNS-SD's existing `QueryCallback` mechanism, enabling
customized discovery proxy implementations, remains supported.

This commit includes a comprehensive unit test. This test validates
the discovery proxy's behavior, covering: standard use cases, request
timeout, s hared resolver/browser usage for multiple queries with the
same name, filtering of invalid addresses, and various edge cases.
This commit is contained in:
Abtin Keshavarzian
2024-06-10 12:16:24 -07:00
committed by GitHub
parent a8f07b57cf
commit 5dbbab175b
17 changed files with 4617 additions and 139 deletions
+1
View File
@@ -201,6 +201,7 @@ ot_option(OT_DNS_CLIENT OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE "DNS client")
ot_option(OT_DNS_CLIENT_OVER_TCP OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_ENABLE "Enable dns query over tcp")
ot_option(OT_DNS_DSO OPENTHREAD_CONFIG_DNS_DSO_ENABLE "DNS Stateful Operations (DSO)")
ot_option(OT_DNS_UPSTREAM_QUERY OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE "Allow sending DNS queries to upstream")
ot_option(OT_DNSSD_DISCOVERY_PROXY OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE "DNS-SD discovery proxy")
ot_option(OT_DNSSD_SERVER OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE "DNS-SD server")
ot_option(OT_DUA OPENTHREAD_CONFIG_DUA_ENABLE "Domain Unicast Address (DUA)")
ot_option(OT_ECDSA OPENTHREAD_CONFIG_ECDSA_ENABLE "ECDSA")
+60
View File
@@ -104,4 +104,64 @@ void otPlatDnssdUnregisterKey(otInstance *aInstance,
OT_UNUSED_VARIABLE(aCallback);
}
void otPlatDnssdStartBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aBrowser);
}
void otPlatDnssdStopBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aBrowser);
}
void otPlatDnssdStartSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
void otPlatDnssdStopSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
void otPlatDnssdStartTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
void otPlatDnssdStopTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
void otPlatDnssdStartIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
void otPlatDnssdStopIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
void otPlatDnssdStartIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
void otPlatDnssdStopIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
#endif // OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (419)
#define OPENTHREAD_API_VERSION (420)
/**
* @addtogroup api-instance
+44 -108
View File
@@ -500,158 +500,94 @@ otError otMdnsGetNextService(otInstance *aInstance,
*/
otError otMdnsGetNextKey(otInstance *aInstance, otMdnsIterator *aIterator, otMdnsKey *aKey, otMdnsEntryState *aState);
typedef struct otMdnsBrowseResult otMdnsBrowseResult;
typedef struct otMdnsSrvResult otMdnsSrvResult;
typedef struct otMdnsTxtResult otMdnsTxtResult;
typedef struct otMdnsAddressResult otMdnsAddressResult;
/**
* Represents the callback function used to report a browse result.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResult The browse result.
*
*/
typedef void (*otMdnsBrowseCallback)(otInstance *aInstance, const otMdnsBrowseResult *aResult);
/**
* Represents the callback function used to report an SRV resolve result.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResult The SRV resolve result.
*
*/
typedef void (*otMdnsSrvCallback)(otInstance *aInstance, const otMdnsSrvResult *aResult);
/**
* Represents the callback function used to report a TXT resolve result.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResult The TXT resolve result.
*
*/
typedef void (*otMdnsTxtCallback)(otInstance *aInstance, const otMdnsTxtResult *aResult);
/**
* Represents the callback function use to report a IPv6/IPv4 address resolve result.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResult The address resolve result.
*
*/
typedef void (*otMdnsAddressCallback)(otInstance *aInstance, const otMdnsAddressResult *aResult);
/**
* Represents a service browser.
*
* Refer to `otPlatDnssdBrowser` for documentation of member fields and `otMdnsStartBrowser()` for how they are used.
*
*/
typedef struct otMdnsBrowser
{
const char *mServiceType; ///< The service type (e.g., "_mt._udp"). MUST NOT include domain name.
const char *mSubTypeLabel; ///< The sub-type label if browsing for sub-type, NULL otherwise.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
otMdnsBrowseCallback mCallback; ///< The callback to report result.
} otMdnsBrowser;
typedef otPlatDnssdBrowser otMdnsBrowser;
/**
* Represents the callback function pointer type used to report a browse result.
*
*/
typedef otPlatDnssdBrowseCallback otMdnsBrowseCallback;
/**
* Represents a browse result.
*
*/
struct otMdnsBrowseResult
{
const char *mServiceType; ///< The service type (e.g., "_mt._udp").
const char *mSubTypeLabel; ///< The sub-type label if browsing for sub-type, NULL otherwise.
const char *mServiceInstance; ///< Service instance label.
uint32_t mTtl; ///< TTL in seconds. Zero TTL indicates that service is removed.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
};
typedef otPlatDnssdBrowseResult otMdnsBrowseResult;
/**
* Represents an SRV service resolver.
*
* Refer to `otPlatDnssdSrvResolver` for documentation of member fields and `otMdnsStartSrvResolver()` for how they are
* used.
*
*/
typedef struct otMdnsSrvResolver
{
const char *mServiceInstance; ///< The service instance label.
const char *mServiceType; ///< The service type.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
otMdnsSrvCallback mCallback; ///< The callback to report result.
} otMdnsSrvResolver;
typedef otPlatDnssdSrvResolver otMdnsSrvResolver;
/**
* Represents the callback function pointer type used to report an SRV resolve result.
*
*/
typedef otPlatDnssdSrvCallback otMdnsSrvCallback;
/**
* Represents an SRV resolver result.
*
*/
struct otMdnsSrvResult
{
const char *mServiceInstance; ///< The service instance name label.
const char *mServiceType; ///< The service type.
const char *mHostName; ///< The host name (e.g., "myhost"). Can be NULL when `mTtl` is zero.
uint16_t mPort; ///< The service port number.
uint16_t mPriority; ///< The service priority.
uint16_t mWeight; ///< The service weight.
uint32_t mTtl; ///< The service TTL in seconds. Zero TTL indicates SRV record is removed.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
};
typedef otPlatDnssdSrvResult otMdnsSrvResult;
/**
* Represents a TXT service resolver.
*
* Refer to `otPlatDnssdTxtResolver` for documentation of member fields and `otMdnsStartTxtResolver()` for how they are
* used.
*
*/
typedef struct otMdnsTxtResolver
{
const char *mServiceInstance; ///< Service instance label.
const char *mServiceType; ///< Service type.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
otMdnsTxtCallback mCallback;
} otMdnsTxtResolver;
typedef otPlatDnssdTxtResolver otMdnsTxtResolver;
/**
* Represents the callback function pointer type used to report a TXT resolve result.
*
*/
typedef otPlatDnssdTxtCallback otMdnsTxtCallback;
/**
* Represents a TXT resolver result.
*
*/
struct otMdnsTxtResult
{
const char *mServiceInstance; ///< The service instance name label.
const char *mServiceType; ///< The service type.
const uint8_t *mTxtData; ///< Encoded TXT data bytes. Can be NULL when `mTtl` is zero.
uint16_t mTxtDataLength; ///< Length of TXT data.
uint32_t mTtl; ///< The TXT data TTL in seconds. Zero TTL indicates record is removed.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
};
typedef otPlatDnssdTxtResult otMdnsTxtResult;
/**
* Represents an address resolver.
*
* Refer to `otPlatDnssdAddressResolver` for documentation of member fields and `otMdnsStartIp6AddressResolver()` or
* `otMdnsStartIp4AddressResolver()` for how they are used.
*
*/
typedef struct otMdnsAddressResolver
{
const char *mHostName; ///< The host name (e.g., "myhost"). MUST NOT contain domain name.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
otMdnsAddressCallback mCallback; ///< The callback to report result.
} otMdnsAddressResolver;
typedef otPlatDnssdAddressResolver otMdnsAddressResolver;
/**
* Represents the callback function pointer type use to report an IPv6/IPv4 address resolve result.
*
*/
typedef otPlatDnssdAddressCallback otMdnsAddressCallback;
/**
* Represents a discovered host address and its TTL.
*
*/
typedef struct otMdnsAddressAndTtl
{
otIp6Address mAddress; ///< The IPv6 address. For IPv4 address the IPv4-mapped IPv6 address format is used.
uint32_t mTtl; ///< The TTL in seconds.
} otMdnsAddressAndTtl;
typedef otPlatDnssdAddressAndTtl otMdnsAddressAndTtl;
/**
* Represents address resolver result.
*
*/
struct otMdnsAddressResult
{
const char *mHostName; ///< The host name.
const otMdnsAddressAndTtl *mAddresses; ///< Array of host addresses and their TTL. Can be NULL if empty.
uint16_t mAddressesLength; ///< Number of entries in `mAddresses` array.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
};
typedef otPlatDnssdAddressResult otMdnsAddressResult;
/**
* Starts a service browser.
+343 -1
View File
@@ -65,7 +65,7 @@ extern "C" {
*/
typedef enum otPlatDnssdState
{
OT_PLAT_DNSSD_STOPPED, ///< Stopped and unable to register any service or host.
OT_PLAT_DNSSD_STOPPED, ///< Stopped and unable to register any service or host, or start any browser/resolver.
OT_PLAT_DNSSD_READY, ///< Running and ready to register service or host.
} otPlatDnssdState;
@@ -149,6 +149,9 @@ typedef struct otPlatDnssdKey
* The OpenThread stack will call `otPlatDnssdGetState()` (from this callback or later) to get the new state. The
* platform MUST therefore ensure that the returned state from `otPlatDnssdGetState()` is updated before calling this.
*
* When the platform signals a state change to `OT_PLAT_DNSSD_STOPPED` using this callback, all active browsers and
* resolvers are considered to be stopped, and any previously registered host, service, key entries as removed.
*
* @param[in] aInstance The OpenThread instance structure.
*
*/
@@ -415,6 +418,345 @@ void otPlatDnssdUnregisterKey(otInstance *aInstance,
otPlatDnssdRequestId aRequestId,
otPlatDnssdRegisterCallback aCallback);
//======================================================================================================================
/**
* Represents a browse result.
*
*/
typedef struct otPlatDnssdBrowseResult
{
const char *mServiceType; ///< The service type (e.g., "_mt._udp").
const char *mSubTypeLabel; ///< The sub-type label if browsing for sub-type, NULL otherwise.
const char *mServiceInstance; ///< Service instance label.
uint32_t mTtl; ///< TTL in seconds. Zero TTL indicates that service is removed.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
} otPlatDnssdBrowseResult;
/**
* Represents the callback function used to report a browse result.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResult The browse result.
*
*/
typedef void (*otPlatDnssdBrowseCallback)(otInstance *aInstance, const otPlatDnssdBrowseResult *aResult);
/**
* Represents a service browser.
*
*/
typedef struct otPlatDnssdBrowser
{
const char *mServiceType; ///< The service type (e.g., "_mt._udp"). MUST NOT include domain name.
const char *mSubTypeLabel; ///< The sub-type label if browsing for sub-type, NULL otherwise.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
otPlatDnssdBrowseCallback mCallback; ///< The callback to report result.
} otPlatDnssdBrowser;
/**
* Represents an SRV resolver result.
*
*/
typedef struct otPlatDnssdSrvResult
{
const char *mServiceInstance; ///< The service instance name label.
const char *mServiceType; ///< The service type.
const char *mHostName; ///< The host name (e.g., "myhost"). Can be NULL when `mTtl` is zero.
uint16_t mPort; ///< The service port number.
uint16_t mPriority; ///< The service priority.
uint16_t mWeight; ///< The service weight.
uint32_t mTtl; ///< The service TTL in seconds. Zero TTL indicates SRV record is removed.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
} otPlatDnssdSrvResult;
/**
* Represents the callback function used to report an SRV resolve result.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResult The SRV resolve result.
*
*/
typedef void (*otPlatDnssdSrvCallback)(otInstance *aInstance, const otPlatDnssdSrvResult *aResult);
/**
* Represents an SRV service resolver.
*
*/
typedef struct otPlatDnssdSrvResolver
{
const char *mServiceInstance; ///< The service instance label.
const char *mServiceType; ///< The service type.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
otPlatDnssdSrvCallback mCallback; ///< The callback to report result.
} otPlatDnssdSrvResolver;
/**
* Represents a TXT resolver result.
*
*/
typedef struct otPlatDnssdTxtResult
{
const char *mServiceInstance; ///< The service instance name label.
const char *mServiceType; ///< The service type.
const uint8_t *mTxtData; ///< Encoded TXT data bytes. Can be NULL when `mTtl` is zero.
uint16_t mTxtDataLength; ///< Length of TXT data.
uint32_t mTtl; ///< The TXT data TTL in seconds. Zero TTL indicates record is removed.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
} otPlatDnssdTxtResult;
/**
* Represents the callback function used to report a TXT resolve result.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResult The TXT resolve result.
*
*/
typedef void (*otPlatDnssdTxtCallback)(otInstance *aInstance, const otPlatDnssdTxtResult *aResult);
/**
* Represents a TXT service resolver.
*
*/
typedef struct otPlatDnssdTxtResolver
{
const char *mServiceInstance; ///< Service instance label.
const char *mServiceType; ///< Service type.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
otPlatDnssdTxtCallback mCallback;
} otPlatDnssdTxtResolver;
/**
* Represents a discovered host address and its TTL.
*
*/
typedef struct otPlatDnssdAddressAndTtl
{
otIp6Address mAddress; ///< The IPv6 address. For IPv4 address the IPv4-mapped IPv6 address format is used.
uint32_t mTtl; ///< The TTL in seconds.
} otPlatDnssdAddressAndTtl;
/**
* Represents address resolver result.
*
*/
typedef struct otPlatDnssdAddressResult
{
const char *mHostName; ///< The host name.
const otPlatDnssdAddressAndTtl *mAddresses; ///< Array of host addresses and their TTL. Can be NULL if empty.
uint16_t mAddressesLength; ///< Number of entries in `mAddresses` array.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
} otPlatDnssdAddressResult;
/**
* Represents the callback function use to report a IPv6/IPv4 address resolve result.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResult The address resolve result.
*
*/
typedef void (*otPlatDnssdAddressCallback)(otInstance *aInstance, const otPlatDnssdAddressResult *aResult);
/**
* Represents an address resolver.
*
*/
typedef struct otPlatDnssdAddressResolver
{
const char *mHostName; ///< The host name (e.g., "myhost"). MUST NOT contain domain name.
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
otPlatDnssdAddressCallback mCallback; ///< The callback to report result.
} otPlatDnssdAddressResolver;
/**
* Starts a service browser.
*
* Initiates a continuous search for the specified `mServiceType` in @p aBrowser. For sub-type services,
* `mSubTypeLabel` specifies the sub-type, for base services, `mSubTypeLabel` is set to NULL.
*
* Discovered services should be reported through the `mCallback` function in @p aBrowser. Services that have been
* removed are reported with a TTL value of zero. The callback may be invoked immediately with cached information
* (if available) and potentially before this function returns. When cached results are used, the reported TTL value
* should reflect the original TTL from the last received response.
*
* Multiple browsers can be started for the same service, provided they use different callback functions.
*
* The @p aBrowser and all its contained information (strings) are only valid during this call. The platform MUST save
* a copy of the information if it wants to retain the information after returning from this function.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aBrowser The browser to be started.
*
*/
void otPlatDnssdStartBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser);
/**
* Stops a service browser.
*
* No action is performed if no matching browser with the same service and callback is currently active.
*
* The @p aBrowser and all its contained information (strings) are only valid during this call. The platform MUST save
* a copy of the information if it wants to retain the information after returning from this function.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aBrowser The browser to stop.
*
*/
void otPlatDnssdStopBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser);
/**
* Starts an SRV record resolver.
*
* Initiates a continuous SRV record resolver for the specified service in @p aResolver.
*
* Discovered information should be reported through the `mCallback` function in @p aResolver. When the service is
* removed it is reported with a TTL value of zero. In this case, `mHostName` may be NULL and other result fields (such
* as `mPort`) will be ignored by the OpenThread stack.
*
* The callback may be invoked immediately with cached information (if available) and potentially before this function
* returns. When cached result is used, the reported TTL value should reflect the original TTL from the last received
* response.
*
* Multiple resolvers can be started for the same service, provided they use different callback functions.
*
* The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save
* a copy of the information if it wants to retain the information after returning from this function.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResolver The resolver to be started.
*
*/
void otPlatDnssdStartSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver);
/**
* Stops an SRV record resolver.
*
* No action is performed if no matching resolver with the same service and callback is currently active.
*
* The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save
* a copy of the information if it wants to retain the information after returning from this function.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResolver The resolver to stop.
*
*/
void otPlatDnssdStopSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver);
/**
* Starts a TXT record resolver.
*
* Initiates a continuous TXT record resolver for the specified service in @p aResolver.
*
* Discovered information should be reported through the `mCallback` function in @p aResolver. When the TXT record is
* removed it is reported with a TTL value of zero. In this case, `mTxtData` may be NULL, and other result fields
* (such as `mTxtDataLength`) will be ignored by the OpenThread stack.
*
* The callback may be invoked immediately with cached information (if available) and potentially before this function
* returns. When cached result is used, the reported TTL value should reflect the original TTL from the last received
* response.
*
* Multiple resolvers can be started for the same service, provided they use different callback functions.
*
* The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save
* a copy of the information if it wants to retain the information after returning from this function.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResolver The resolver to be started.
*
*/
void otPlatDnssdStartTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver);
/**
* Stops a TXT record resolver.
*
* No action is performed if no matching resolver with the same service and callback is currently active.
*
* The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save
* a copy of the information if it wants to retain the information after returning from this function.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResolver The resolver to stop.
*
*/
void otPlatDnssdStopTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver);
/**
* Starts an IPv6 address resolver.
*
* Initiates a continuous IPv6 address resolver for the specified host name in @p aResolver.
*
* Discovered addresses should be reported through the `mCallback` function in @p aResolver. The callback should be
* invoked whenever addresses are added or removed, providing an updated list. If all addresses are removed, the
* callback should be invoked with an empty list (`mAddressesLength` set to zero).
*
* The callback may be invoked immediately with cached information (if available) and potentially before this function
* returns. When cached result is used, the reported TTL values should reflect the original TTL from the last received
* response.
*
* Multiple resolvers can be started for the same host name, provided they use different callback functions.
*
* The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save
* a copy of the information if it wants to retain the information after returning from this function.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResolver The resolver to be started.
*
*/
void otPlatDnssdStartIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver);
/**
* Stops an IPv6 address resolver.
*
* No action is performed if no matching resolver with the same host name and callback is currently active.
*
* The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save
* a copy of the information if it wants to retain the information after returning from this function.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResolver The resolver to stop.
*
*/
void otPlatDnssdStopIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver);
/**
* Starts an IPv4 address resolver.
*
* Initiates a continuous IPv4 address resolver for the specified host name in @p aResolver.
*
* Discovered addresses should be reported through the `mCallback` function in @p aResolver. The IPv4 addresses are
* represented using the IPv4-mapped IPv6 address format in `mAddresses` array. The callback should be invoked
* whenever addresses are added or removed, providing an updated list. If all addresses are removed, the callback
* should be invoked with an empty list (`mAddressesLength` set to zero).
*
* The callback may be invoked immediately with cached information (if available) and potentially before this function
* returns. When cached result is used, the reported TTL values will reflect the original TTL from the last received
* response.
*
* Multiple resolvers can be started for the same host name, provided they use different callback functions.
*
* The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save
* a copy of the information if it wants to retain the information after returning from this function.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResolver The resolver to be started.
*
*/
void otPlatDnssdStartIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver);
/**
* Stops an IPv4 address resolver.
*
* No action is performed if no matching resolver with the same host name and callback is currently active.
*
* The @p aResolver and all its contained information (strings) are only valid during this call. The platform MUST save
* a copy of the information if it wants to retain the information after returning from this function.
*
* @param[in] aInstance The OpenThread instance.
* @param[in] aResolver The resolver to stop.
*
*/
void otPlatDnssdStopIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver);
/**
* @}
*
+2
View File
@@ -52,6 +52,8 @@ OT_BUILD_OPTIONS=(
"-DOT_DHCP6_CLIENT=ON"
"-DOT_DHCP6_SERVER=ON"
"-DOT_DIAGNOSTIC=ON"
"-DOT_DNSSD_DISCOVERY_PROXY=ON"
"-DOT_DNSSD_SERVER=ON"
"-DOT_DNS_CLIENT=ON"
"-DOT_DNS_DSO=ON"
"-DOT_ECDSA=ON"
+1
View File
@@ -110,6 +110,7 @@ OT_CLANG_TIDY_BUILD_OPTS=(
'-DOT_DNS_CLIENT=ON'
'-DOT_DNS_DSO=ON'
'-DOT_DNS_UPSTREAM_QUERY=ON'
"-DOT_DNSSD_DISCOVERY_PROXY=ON"
'-DOT_DNSSD_SERVER=ON'
'-DOT_DUA=ON'
'-DOT_MLR=ON'
+4
View File
@@ -156,6 +156,10 @@ Error InfraIf::HandleStateChanged(uint32_t aIfIndex, bool aIsRunning)
Get<Srp::AdvertisingProxy>().HandleInfraIfStateChanged();
#endif
#if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE && OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
Get<Dns::ServiceDiscovery::Server>().HandleInfraIfStateChanged();
#endif
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_CONFIG_MULTICAST_DNS_AUTO_ENABLE_ON_INFRA_IF
Get<Dns::Multicast::Core>().HandleInfraIfStateChanged();
#endif
+10
View File
@@ -85,6 +85,16 @@
#define OPENTHREAD_CONFIG_DNSSD_QUERY_TIMEOUT 6000
#endif
/**
* @def OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
*
* Define to 1 to enable DNS-SD Discovery Proxy support.
*
*/
#ifndef OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
#define OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE 0
#endif
/**
* @def OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
*
+233 -7
View File
@@ -255,6 +255,237 @@ exit:
return;
}
void Dnssd::StartBrowser(const Browser &aBrowser)
{
VerifyOrExit(IsReady());
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION
if (mUseNativeMdns)
#endif
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
{
IgnoreError(Get<Dns::Multicast::Core>().StartBrowser(aBrowser));
ExitNow();
}
#endif
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
otPlatDnssdStartBrowser(&GetInstance(), &aBrowser);
#endif
exit:
return;
}
void Dnssd::StopBrowser(const Browser &aBrowser)
{
VerifyOrExit(IsReady());
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION
if (mUseNativeMdns)
#endif
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
{
IgnoreError(Get<Dns::Multicast::Core>().StopBrowser(aBrowser));
ExitNow();
}
#endif
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
otPlatDnssdStopBrowser(&GetInstance(), &aBrowser);
#endif
exit:
return;
}
void Dnssd::StartSrvResolver(const SrvResolver &aResolver)
{
VerifyOrExit(IsReady());
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION
if (mUseNativeMdns)
#endif
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
{
IgnoreError(Get<Dns::Multicast::Core>().StartSrvResolver(aResolver));
ExitNow();
}
#endif
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
otPlatDnssdStartSrvResolver(&GetInstance(), &aResolver);
#endif
exit:
return;
}
void Dnssd::StopSrvResolver(const SrvResolver &aResolver)
{
VerifyOrExit(IsReady());
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION
if (mUseNativeMdns)
#endif
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
{
IgnoreError(Get<Dns::Multicast::Core>().StopSrvResolver(aResolver));
ExitNow();
}
#endif
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
otPlatDnssdStopSrvResolver(&GetInstance(), &aResolver);
#endif
exit:
return;
}
void Dnssd::StartTxtResolver(const TxtResolver &aResolver)
{
VerifyOrExit(IsReady());
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION
if (mUseNativeMdns)
#endif
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
{
IgnoreError(Get<Dns::Multicast::Core>().StartTxtResolver(aResolver));
ExitNow();
}
#endif
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
otPlatDnssdStartTxtResolver(&GetInstance(), &aResolver);
#endif
exit:
return;
}
void Dnssd::StopTxtResolver(const TxtResolver &aResolver)
{
VerifyOrExit(IsReady());
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION
if (mUseNativeMdns)
#endif
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
{
IgnoreError(Get<Dns::Multicast::Core>().StopTxtResolver(aResolver));
ExitNow();
}
#endif
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
otPlatDnssdStopTxtResolver(&GetInstance(), &aResolver);
#endif
exit:
return;
}
void Dnssd::StartIp6AddressResolver(const AddressResolver &aResolver)
{
VerifyOrExit(IsReady());
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION
if (mUseNativeMdns)
#endif
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
{
IgnoreError(Get<Dns::Multicast::Core>().StartIp6AddressResolver(aResolver));
ExitNow();
}
#endif
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
otPlatDnssdStartIp6AddressResolver(&GetInstance(), &aResolver);
#endif
exit:
return;
}
void Dnssd::StopIp6AddressResolver(const AddressResolver &aResolver)
{
VerifyOrExit(IsReady());
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION
if (mUseNativeMdns)
#endif
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
{
IgnoreError(Get<Dns::Multicast::Core>().StopIp6AddressResolver(aResolver));
ExitNow();
}
#endif
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
otPlatDnssdStopIp6AddressResolver(&GetInstance(), &aResolver);
#endif
exit:
return;
}
void Dnssd::StartIp4AddressResolver(const AddressResolver &aResolver)
{
VerifyOrExit(IsReady());
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION
if (mUseNativeMdns)
#endif
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
{
IgnoreError(Get<Dns::Multicast::Core>().StartIp4AddressResolver(aResolver));
ExitNow();
}
#endif
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
otPlatDnssdStartIp4AddressResolver(&GetInstance(), &aResolver);
#endif
exit:
return;
}
void Dnssd::StopIp4AddressResolver(const AddressResolver &aResolver)
{
VerifyOrExit(IsReady());
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION
if (mUseNativeMdns)
#endif
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
{
IgnoreError(Get<Dns::Multicast::Core>().StopIp4AddressResolver(aResolver));
ExitNow();
}
#endif
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
otPlatDnssdStopIp4AddressResolver(&GetInstance(), &aResolver);
#endif
exit:
return;
}
void Dnssd::HandleStateChange(void)
{
#if OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE
Get<Srp::AdvertisingProxy>().HandleDnssdPlatformStateChange();
#endif
#if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE && OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
Get<Dns::ServiceDiscovery::Server>().HandleDnssdPlatformStateChange();
#endif
}
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
void Dnssd::HandleMdnsCoreStateChange(void)
{
@@ -267,17 +498,12 @@ void Dnssd::HandleMdnsCoreStateChange(void)
}
#endif
void Dnssd::HandleStateChange(void)
{
#if OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE
Get<Srp::AdvertisingProxy>().HandleDnssdPlatformStateChange();
#endif
}
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
extern "C" void otPlatDnssdStateHandleStateChange(otInstance *aInstance)
{
AsCoreType(aInstance).Get<Dnssd>().HandleStateChange();
}
#endif
} // namespace ot
+135
View File
@@ -93,6 +93,15 @@ public:
typedef otPlatDnssdRequestId RequestId; ///< A request ID.
typedef otPlatDnssdRegisterCallback RegisterCallback; ///< The registration request callback
typedef otPlatDnssdBrowseCallback BrowseCallback; ///< Browser callback.
typedef otPlatDnssdSrvCallback SrvCallback; ///< SRV callback.
typedef otPlatDnssdTxtCallback TxtCallback; ///< TXT callback.
typedef otPlatDnssdAddressCallback AddressCallback; ///< Address callback
typedef otPlatDnssdBrowseResult BrowseResult; ///< Browser result.
typedef otPlatDnssdSrvResult SrvResult; ///< SRV result.
typedef otPlatDnssdTxtResult TxtResult; ///< TXT result.
typedef otPlatDnssdAddressResult AddressResult; ///< Address result.
typedef otPlatDnssdAddressAndTtl AddressAndTtl; ///< Address and TTL.
class Host : public otPlatDnssdHost, public Clearable<Host> ///< Host information.
{
@@ -106,6 +115,22 @@ public:
{
};
class Browser : public otPlatDnssdBrowser, public Clearable<Browser> ///< Browser.
{
};
class SrvResolver : public otPlatDnssdSrvResolver, public Clearable<SrvResolver> ///< SRV resolver.
{
};
class TxtResolver : public otPlatDnssdTxtResolver, public Clearable<TxtResolver> ///< TXT resolver.
{
};
class AddressResolver : public otPlatDnssdAddressResolver, public Clearable<AddressResolver> ///< Address resolver.
{
};
/**
* Represents a range of `RequestId` values.
*
@@ -274,6 +299,116 @@ public:
*/
void UnregisterKey(const Key &aKey, RequestId aRequestId, RegisterCallback aCallback);
/**
* Starts a service browser.
*
* Refer to the documentation for `otPlatDnssdStartBrowser()` for a more detailed description of the behavior
* of this method.
*
* @param[in] aBrowser The browser to be started.
*
*/
void StartBrowser(const Browser &aBrowser);
/**
* Stops a service browser.
*
* Refer to the documentation for `otPlatDnssdStopBrowser()` for a more detailed description of the behavior
* of this method.
*
* @param[in] aBrowser The browser to stop.
*
*/
void StopBrowser(const Browser &aBrowser);
/**
* Starts an SRV record resolver.
*
* Refer to the documentation for `otPlatDnssdStartSrvResolver()` for a more detailed description of the behavior
* of this method.
*
* @param[in] aResolver The resolver to be started.
*
*/
void StartSrvResolver(const SrvResolver &aResolver);
/**
* Stops an SRV record resolver.
*
* Refer to the documentation for `otPlatDnssdStopSrvResolver()` for a more detailed description of the behavior
* of this method.
*
* @param[in] aResolver The resolver to stop.
*
*/
void StopSrvResolver(const SrvResolver &aResolver);
/**
* Starts a TXT record resolver.
*
* Refer to the documentation for `otPlatDnssdStartTxtResolver()` for a more detailed description of the behavior
* of this method.
*
* @param[in] aResolver The resolver to be started.
*
*/
void StartTxtResolver(const TxtResolver &aResolver);
/**
* Stops a TXT record resolver.
*
* Refer to the documentation for `otPlatDnssdStopTxtResolver()` for a more detailed description of the behavior
* of this method.
*
* @param[in] aResolver The resolver to stop.
*
*/
void StopTxtResolver(const TxtResolver &aResolver);
/**
* Starts an IPv6 address resolver.
*
* Refer to the documentation for `otPlatDnssdStartIp6AddressResolver()` for a more detailed description of the
* behavior of this method.
*
* @param[in] aResolver The resolver to be started.
*
*/
void StartIp6AddressResolver(const AddressResolver &aResolver);
/**
* Stops an IPv6 address resolver.
*
* Refer to the documentation for `otPlatDnssdStopIp6AddressResolver()` for a more detailed description of the
* behavior of this method.
*
* @param[in] aResolver The resolver to stop.
*
*/
void StopIp6AddressResolver(const AddressResolver &aResolver);
/**
* Starts an IPv4 address resolver.
*
* Refer to the documentation for `otPlatDnssdStartIp4AddressResolver()` for a more detailed description of the
* behavior of this method.
*
* @param[in] aResolver The resolver to be started.
*
*/
void StartIp4AddressResolver(const AddressResolver &aResolver);
/**
* Stops an IPv4 address resolver.
*
* Refer to the documentation for `otPlatDnssdStopIp4AddressResolver()` for a more detailed description of the
* behavior of this method.
*
* @param[in] aResolver The resolver to stop.
*
*/
void StopIp4AddressResolver(const AddressResolver &aResolver);
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
/**
* Handles native mDNS state change.
+848 -17
View File
@@ -64,6 +64,9 @@ const char *Server::kBlockedDomains[] = {"ipv4only.arpa."};
Server::Server(Instance &aInstance)
: InstanceLocator(aInstance)
, mSocket(aInstance)
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
, mDiscoveryProxy(aInstance)
#endif
#if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
, mEnableUpstreamQuery(false)
#endif
@@ -88,6 +91,10 @@ Error Server::Start(void)
LogInfo("Started");
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
mDiscoveryProxy.UpdateState();
#endif
exit:
if (error != kErrorNone)
{
@@ -104,6 +111,10 @@ void Server::Stop(void)
Finalize(query, Header::kResponseServerFailure);
}
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
mDiscoveryProxy.Stop();
#endif
#if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
for (UpstreamQueryTransaction &txn : mUpstreamQueryTransactions)
{
@@ -586,22 +597,30 @@ Error Server::Response::AppendHostAddresses(const Ip6::Address *aAddrs, uint16_t
for (uint16_t index = 0; index < aAddrsLength; index++)
{
AaaaRecord aaaaRecord;
aaaaRecord.Init();
aaaaRecord.SetTtl(aTtl);
aaaaRecord.SetAddress(aAddrs[index]);
SuccessOrExit(error = Name::AppendPointerLabel(mOffsets.mHostName, *mMessage));
SuccessOrExit(error = mMessage->Append(aaaaRecord));
IncResourceRecordCount();
SuccessOrExit(error = AppendAaaaRecord(aAddrs[index], aTtl));
}
exit:
return error;
}
Error Server::Response::AppendAaaaRecord(const Ip6::Address &aAddress, uint32_t aTtl)
{
Error error;
AaaaRecord aaaaRecord;
aaaaRecord.Init();
aaaaRecord.SetTtl(aTtl);
aaaaRecord.SetAddress(aAddress);
SuccessOrExit(error = Name::AppendPointerLabel(mOffsets.mHostName, *mMessage));
SuccessOrExit(error = mMessage->Append(aaaaRecord));
IncResourceRecordCount();
exit:
return error;
}
#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
Error Server::Response::AppendTxtRecord(const Srp::Server::Service &aService)
{
@@ -915,9 +934,12 @@ void Server::ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessag
{
ProxyQuery *query;
ProxyQueryInfo info;
Name::Buffer name;
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
VerifyOrExit(mQuerySubscribe.IsSet() || mDiscoveryProxy.IsRunning());
#else
VerifyOrExit(mQuerySubscribe.IsSet());
#endif
// We try to convert `aResponse.mMessage` to a `ProxyQuery` by
// appending `ProxyQueryInfo` to it.
@@ -927,6 +949,10 @@ void Server::ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessag
info.mExpireTime = TimerMilli::GetNow() + kQueryTimeout;
info.mOffsets = aResponse.mOffsets;
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
info.mAction = kNoAction;
#endif
if (aResponse.mMessage->Append(info) != kErrorNone)
{
aResponse.SetResponseCode(Header::kResponseServerFailure);
@@ -943,8 +969,21 @@ void Server::ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessag
mTimer.FireAtIfEarlier(info.mExpireTime);
ReadQueryName(*query, name);
mQuerySubscribe.Invoke(name);
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
if (mQuerySubscribe.IsSet())
#endif
{
Name::Buffer name;
ReadQueryName(*query, name);
mQuerySubscribe.Invoke(name);
}
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
else
{
mDiscoveryProxy.Resolve(*query, info);
}
#endif
exit:
return;
@@ -964,6 +1003,91 @@ bool Server::QueryNameMatches(const Message &aQuery, const char *aName)
return (Name::CompareName(aQuery, offset, aName) == kErrorNone);
}
void Server::ReadQueryInstanceName(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Name::Buffer &aName)
{
uint16_t offset = aInfo.mOffsets.mInstanceName;
IgnoreError(Name::ReadName(aQuery, offset, aName, sizeof(aName)));
}
void Server::ReadQueryInstanceName(const ProxyQuery &aQuery,
const ProxyQueryInfo &aInfo,
Name::LabelBuffer &aInstanceLabel,
Name::Buffer &aServiceType)
{
// Reads the service instance label and service type with domain
// name stripped.
uint16_t offset = aInfo.mOffsets.mInstanceName;
uint8_t labelLength = sizeof(aInstanceLabel);
IgnoreError(Dns::Name::ReadLabel(aQuery, offset, aInstanceLabel, labelLength));
IgnoreError(Dns::Name::ReadName(aQuery, offset, aServiceType));
IgnoreError(StripDomainName(aServiceType));
}
bool Server::QueryInstanceNameMatches(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, const char *aName)
{
uint16_t offset = aInfo.mOffsets.mInstanceName;
return (Name::CompareName(aQuery, offset, aName) == kErrorNone);
}
void Server::ReadQueryHostName(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Name::Buffer &aName)
{
uint16_t offset = aInfo.mOffsets.mHostName;
IgnoreError(Name::ReadName(aQuery, offset, aName, sizeof(aName)));
}
bool Server::QueryHostNameMatches(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, const char *aName)
{
uint16_t offset = aInfo.mOffsets.mHostName;
return (Name::CompareName(aQuery, offset, aName) == kErrorNone);
}
Error Server::StripDomainName(Name::Buffer &aName)
{
// In-place removes the domain name from `aName`.
return Name::StripName(aName, kDefaultDomainName);
}
Error Server::StripDomainName(const char *aFullName, Name::Buffer &aLabels)
{
// Remove the domain name from `aFullName` and copies
// the result into `aLabels`.
return Name::ExtractLabels(aFullName, kDefaultDomainName, aLabels, sizeof(aLabels));
}
void Server::ConstructFullName(const char *aLabels, Name::Buffer &aFullName)
{
// Construct a full name by appending the default domain name
// to `aLabels`.
StringWriter fullName(aFullName, sizeof(aFullName));
fullName.Append("%s.%s", aLabels, kDefaultDomainName);
}
void Server::ConstructFullInstanceName(const char *aInstanceLabel, const char *aServiceType, Name::Buffer &aFullName)
{
StringWriter fullName(aFullName, sizeof(aFullName));
fullName.Append("%s.%s.%s", aInstanceLabel, aServiceType, kDefaultDomainName);
}
void Server::ConstructFullServiceSubTypeName(const char *aServiceType,
const char *aSubTypeLabel,
Name::Buffer &aFullName)
{
StringWriter fullName(aFullName, sizeof(aFullName));
fullName.Append("%s._sub.%s.%s", aSubTypeLabel, aServiceType, kDefaultDomainName);
}
void Server::ProxyQueryInfo::ReadFrom(const ProxyQuery &aQuery)
{
SuccessOrAssert(aQuery.Read(aQuery.GetLength() - sizeof(ProxyQueryInfo), *this));
@@ -987,15 +1111,22 @@ Error Server::Response::ExtractServiceInstanceLabel(const char *aInstanceName, N
return Name::ExtractLabels(aInstanceName, serviceName, aLabel);
}
void Server::RemoveQueryAndPrepareResponse(ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Response &aResponse)
void Server::RemoveQueryAndPrepareResponse(ProxyQuery &aQuery, ProxyQueryInfo &aInfo, Response &aResponse)
{
Name::Buffer name;
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
mDiscoveryProxy.CancelAction(aQuery, aInfo);
#endif
mProxyQueries.Dequeue(aQuery);
aInfo.RemoveFrom(aQuery);
ReadQueryName(aQuery, name);
mQueryUnsubscribe.InvokeIfSet(name);
if (mQueryUnsubscribe.IsSet())
{
Name::Buffer name;
ReadQueryName(aQuery, name);
mQueryUnsubscribe.Invoke(name);
}
aResponse.InitFrom(aQuery, aInfo);
}
@@ -1282,6 +1413,706 @@ void Server::ResetUpstreamQueryTransaction(UpstreamQueryTransaction &aTxn, Error
}
#endif
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
Server::DiscoveryProxy::DiscoveryProxy(Instance &aInstance)
: InstanceLocator(aInstance)
, mIsRunning(false)
{
}
void Server::DiscoveryProxy::UpdateState(void)
{
if (Get<Server>().IsRunning() && Get<Dnssd>().IsReady() && Get<BorderRouter::InfraIf>().IsRunning())
{
Start();
}
else
{
Stop();
}
}
void Server::DiscoveryProxy::Start(void)
{
VerifyOrExit(!mIsRunning);
mIsRunning = true;
LogInfo("Started discovery proxy");
exit:
return;
}
void Server::DiscoveryProxy::Stop(void)
{
VerifyOrExit(mIsRunning);
for (ProxyQuery &query : Get<Server>().mProxyQueries)
{
Get<Server>().Finalize(query, Header::kResponseSuccess);
}
mIsRunning = false;
LogInfo("Stopped discovery proxy");
exit:
return;
}
void Server::DiscoveryProxy::Resolve(ProxyQuery &aQuery, ProxyQueryInfo &aInfo)
{
ProxyAction action = kNoAction;
switch (aInfo.mType)
{
case kPtrQuery:
action = kBrowsing;
break;
case kSrvQuery:
case kSrvTxtQuery:
action = kResolvingSrv;
break;
case kTxtQuery:
action = kResolvingTxt;
break;
case kAaaaQuery:
action = kResolvingIp6Address;
break;
}
Perform(action, aQuery, aInfo);
}
void Server::DiscoveryProxy::Perform(ProxyAction aAction, ProxyQuery &aQuery, ProxyQueryInfo &aInfo)
{
bool shouldStart;
Name::Buffer name;
VerifyOrExit(aAction != kNoAction);
// The order of the steps below is crucial. First, we read the
// name associated with the action. Then we check if another
// query has an active browser/resolver for the same name. This
// helps us determine if a new browser/resolver is needed. Then,
// we update the `ProxyQueryInfo` within `aQuery` to reflect the
// `aAction` being performed. Finally, if necessary, we start the
// proper browser/resolver on DNS-SD/mDNS. Placing this last
// ensures correct processing even if a DNS-SD/mDNS callback is
// invoked immediately.
ReadNameFor(aAction, aQuery, aInfo, name);
shouldStart = !HasActive(aAction, name);
aInfo.mAction = aAction;
aInfo.UpdateIn(aQuery);
VerifyOrExit(shouldStart);
UpdateProxy(kStart, aAction, aQuery, aInfo, name);
exit:
return;
}
void Server::DiscoveryProxy::ReadNameFor(ProxyAction aAction,
ProxyQuery &aQuery,
ProxyQueryInfo &aInfo,
Name::Buffer &aName) const
{
// Read the name corresponding to `aAction` from `aQuery`.
switch (aAction)
{
case kNoAction:
break;
case kBrowsing:
ReadQueryName(aQuery, aName);
break;
case kResolvingSrv:
case kResolvingTxt:
ReadQueryInstanceName(aQuery, aInfo, aName);
break;
case kResolvingIp6Address:
ReadQueryHostName(aQuery, aInfo, aName);
break;
}
}
void Server::DiscoveryProxy::CancelAction(ProxyQuery &aQuery, ProxyQueryInfo &aInfo)
{
// Cancel the current action for a given `aQuery`, then
// determine if we need to stop any browser/resolver
// on infrastructure.
ProxyAction action = aInfo.mAction;
Name::Buffer name;
VerifyOrExit(mIsRunning);
VerifyOrExit(action != kNoAction);
// We first update the `aInfo` on `aQuery` before calling
// `HasActive()`. This ensures that the current query is not
// taken into account when we try to determine if any query
// is waiting for same `aAction` browser/resolver.
ReadNameFor(action, aQuery, aInfo, name);
aInfo.mAction = kNoAction;
aInfo.UpdateIn(aQuery);
VerifyOrExit(!HasActive(action, name));
UpdateProxy(kStop, action, aQuery, aInfo, name);
exit:
return;
}
void Server::DiscoveryProxy::UpdateProxy(Command aCommand,
ProxyAction aAction,
const ProxyQuery &aQuery,
const ProxyQueryInfo &aInfo,
Name::Buffer &aName)
{
// Start or stop browser/resolver corresponding to `aAction`.
// `aName` may be changed.
switch (aAction)
{
case kNoAction:
break;
case kBrowsing:
StartOrStopBrowser(aCommand, aName);
break;
case kResolvingSrv:
StartOrStopSrvResolver(aCommand, aQuery, aInfo);
break;
case kResolvingTxt:
StartOrStopTxtResolver(aCommand, aQuery, aInfo);
break;
case kResolvingIp6Address:
StartOrStopIp6Resolver(aCommand, aName);
break;
}
}
void Server::DiscoveryProxy::StartOrStopBrowser(Command aCommand, Name::Buffer &aServiceName)
{
// Start or stop a service browser for a given service type
// or sub-type.
static const char kFullSubLabel[] = "._sub.";
Dnssd::Browser browser;
char *ptr;
browser.Clear();
IgnoreError(StripDomainName(aServiceName));
// Check if the service name is a sub-type with name
// format: "<sub-label>._sub.<service-labels>.
ptr = AsNonConst(StringFind(aServiceName, kFullSubLabel, kStringCaseInsensitiveMatch));
if (ptr != nullptr)
{
*ptr = kNullChar;
ptr += sizeof(kFullSubLabel) - 1;
browser.mServiceType = ptr;
browser.mSubTypeLabel = aServiceName;
}
else
{
browser.mServiceType = aServiceName;
browser.mSubTypeLabel = nullptr;
}
browser.mInfraIfIndex = Get<BorderRouter::InfraIf>().GetIfIndex();
browser.mCallback = HandleBrowseResult;
switch (aCommand)
{
case kStart:
Get<Dnssd>().StartBrowser(browser);
break;
case kStop:
Get<Dnssd>().StopBrowser(browser);
break;
}
}
void Server::DiscoveryProxy::StartOrStopSrvResolver(Command aCommand,
const ProxyQuery &aQuery,
const ProxyQueryInfo &aInfo)
{
// Start or stop an SRV record resolver for a given query.
Dnssd::SrvResolver resolver;
Name::LabelBuffer instanceLabel;
Name::Buffer serviceType;
ReadQueryInstanceName(aQuery, aInfo, instanceLabel, serviceType);
resolver.Clear();
resolver.mServiceInstance = instanceLabel;
resolver.mServiceType = serviceType;
resolver.mInfraIfIndex = Get<BorderRouter::InfraIf>().GetIfIndex();
resolver.mCallback = HandleSrvResult;
switch (aCommand)
{
case kStart:
Get<Dnssd>().StartSrvResolver(resolver);
break;
case kStop:
Get<Dnssd>().StopSrvResolver(resolver);
break;
}
}
void Server::DiscoveryProxy::StartOrStopTxtResolver(Command aCommand,
const ProxyQuery &aQuery,
const ProxyQueryInfo &aInfo)
{
// Start or stop a TXT record resolver for a given query.
Dnssd::TxtResolver resolver;
Name::LabelBuffer instanceLabel;
Name::Buffer serviceType;
ReadQueryInstanceName(aQuery, aInfo, instanceLabel, serviceType);
resolver.Clear();
resolver.mServiceInstance = instanceLabel;
resolver.mServiceType = serviceType;
resolver.mInfraIfIndex = Get<BorderRouter::InfraIf>().GetIfIndex();
resolver.mCallback = HandleTxtResult;
switch (aCommand)
{
case kStart:
Get<Dnssd>().StartTxtResolver(resolver);
break;
case kStop:
Get<Dnssd>().StopTxtResolver(resolver);
break;
}
}
void Server::DiscoveryProxy::StartOrStopIp6Resolver(Command aCommand, Name::Buffer &aHostName)
{
// Start or stop an IPv6 address resolver for a given host name.
Dnssd::AddressResolver resolver;
IgnoreError(StripDomainName(aHostName));
resolver.mHostName = aHostName;
resolver.mInfraIfIndex = Get<BorderRouter::InfraIf>().GetIfIndex();
resolver.mCallback = HandleIp6AddressResult;
switch (aCommand)
{
case kStart:
Get<Dnssd>().StartIp6AddressResolver(resolver);
break;
case kStop:
Get<Dnssd>().StopIp6AddressResolver(resolver);
break;
}
}
bool Server::DiscoveryProxy::QueryMatches(const ProxyQuery &aQuery,
const ProxyQueryInfo &aInfo,
ProxyAction aAction,
const Name::Buffer &aName) const
{
// Check whether `aQuery` is performing `aAction` and
// its name matches `aName`.
bool matches = false;
VerifyOrExit(aInfo.mAction == aAction);
switch (aAction)
{
case kBrowsing:
VerifyOrExit(QueryNameMatches(aQuery, aName));
break;
case kResolvingSrv:
case kResolvingTxt:
VerifyOrExit(QueryInstanceNameMatches(aQuery, aInfo, aName));
break;
case kResolvingIp6Address:
VerifyOrExit(QueryHostNameMatches(aQuery, aInfo, aName));
break;
case kNoAction:
ExitNow();
}
matches = true;
exit:
return matches;
}
bool Server::DiscoveryProxy::HasActive(ProxyAction aAction, const Name::Buffer &aName) const
{
// Determine whether or not we have an active browser/resolver
// corresponding to `aAction` for `aName`.
bool has = false;
for (const ProxyQuery &query : Get<Server>().mProxyQueries)
{
ProxyQueryInfo info;
info.ReadFrom(query);
if (QueryMatches(query, info, aAction, aName))
{
has = true;
break;
}
}
return has;
}
void Server::DiscoveryProxy::HandleBrowseResult(otInstance *aInstance, const otPlatDnssdBrowseResult *aResult)
{
AsCoreType(aInstance).Get<Server>().mDiscoveryProxy.HandleBrowseResult(*aResult);
}
void Server::DiscoveryProxy::HandleBrowseResult(const Dnssd::BrowseResult &aResult)
{
Name::Buffer serviceName;
VerifyOrExit(mIsRunning);
VerifyOrExit(aResult.mTtl != 0);
VerifyOrExit(aResult.mInfraIfIndex == Get<BorderRouter::InfraIf>().GetIfIndex());
if (aResult.mSubTypeLabel != nullptr)
{
ConstructFullServiceSubTypeName(aResult.mServiceType, aResult.mSubTypeLabel, serviceName);
}
else
{
ConstructFullName(aResult.mServiceType, serviceName);
}
HandleResult(kBrowsing, serviceName, &Response::AppendPtrRecord, ProxyResult(aResult));
exit:
return;
}
void Server::DiscoveryProxy::HandleSrvResult(otInstance *aInstance, const otPlatDnssdSrvResult *aResult)
{
AsCoreType(aInstance).Get<Server>().mDiscoveryProxy.HandleSrvResult(*aResult);
}
void Server::DiscoveryProxy::HandleSrvResult(const Dnssd::SrvResult &aResult)
{
Name::Buffer instanceName;
VerifyOrExit(mIsRunning);
VerifyOrExit(aResult.mTtl != 0);
VerifyOrExit(aResult.mInfraIfIndex == Get<BorderRouter::InfraIf>().GetIfIndex());
ConstructFullInstanceName(aResult.mServiceInstance, aResult.mServiceType, instanceName);
HandleResult(kResolvingSrv, instanceName, &Response::AppendSrvRecord, ProxyResult(aResult));
exit:
return;
}
void Server::DiscoveryProxy::HandleTxtResult(otInstance *aInstance, const otPlatDnssdTxtResult *aResult)
{
AsCoreType(aInstance).Get<Server>().mDiscoveryProxy.HandleTxtResult(*aResult);
}
void Server::DiscoveryProxy::HandleTxtResult(const Dnssd::TxtResult &aResult)
{
Name::Buffer instanceName;
VerifyOrExit(mIsRunning);
VerifyOrExit(aResult.mTtl != 0);
VerifyOrExit(aResult.mInfraIfIndex == Get<BorderRouter::InfraIf>().GetIfIndex());
ConstructFullInstanceName(aResult.mServiceInstance, aResult.mServiceType, instanceName);
HandleResult(kResolvingTxt, instanceName, &Response::AppendTxtRecord, ProxyResult(aResult));
exit:
return;
}
void Server::DiscoveryProxy::HandleIp6AddressResult(otInstance *aInstance, const otPlatDnssdAddressResult *aResult)
{
AsCoreType(aInstance).Get<Server>().mDiscoveryProxy.HandleIp6AddressResult(*aResult);
}
void Server::DiscoveryProxy::HandleIp6AddressResult(const Dnssd::AddressResult &aResult)
{
bool hasValidAddress = false;
Name::Buffer fullHostName;
VerifyOrExit(mIsRunning);
VerifyOrExit(aResult.mInfraIfIndex == Get<BorderRouter::InfraIf>().GetIfIndex());
for (uint16_t index = 0; index < aResult.mAddressesLength; index++)
{
const Dnssd::AddressAndTtl &entry = aResult.mAddresses[index];
const Ip6::Address &address = AsCoreType(&entry.mAddress);
if (entry.mTtl == 0)
{
continue;
}
if (IsProxyAddressValid(address))
{
hasValidAddress = true;
break;
}
}
VerifyOrExit(hasValidAddress);
ConstructFullName(aResult.mHostName, fullHostName);
HandleResult(kResolvingIp6Address, fullHostName, &Response::AppendHostAddresses, ProxyResult(aResult));
exit:
return;
}
void Server::DiscoveryProxy::HandleResult(ProxyAction aAction,
const Name::Buffer &aName,
ResponseAppender aAppender,
const ProxyResult &aResult)
{
// Common method that handles result from DNS-SD/mDNS. It
// iterates over all `ProxyQuery` entries and checks if any entry
// is waiting for the result of `aAction` for `aName`. Matching
// queries are updated using the `aAppender` method pointer,
// which appends the corresponding record(s) to the response. We
// then determine the next action to be performed for the
// `ProxyQuery` or if it can be finalized.
ProxyQueryList nextActionQueries;
ProxyQueryInfo info;
ProxyAction nextAction;
for (ProxyQuery &query : Get<Server>().mProxyQueries)
{
Response response(GetInstance());
bool shouldFinalize;
info.ReadFrom(query);
if (!QueryMatches(query, info, aAction, aName))
{
continue;
}
CancelAction(query, info);
nextAction = kNoAction;
switch (aAction)
{
case kBrowsing:
nextAction = kResolvingSrv;
break;
case kResolvingSrv:
nextAction = (info.mType == kSrvQuery) ? kResolvingIp6Address : kResolvingTxt;
break;
case kResolvingTxt:
nextAction = (info.mType == kTxtQuery) ? kNoAction : kResolvingIp6Address;
break;
case kNoAction:
case kResolvingIp6Address:
break;
}
shouldFinalize = (nextAction == kNoAction);
if ((Get<Server>().mTestMode & kTestModeEmptyAdditionalSection) &&
IsActionForAdditionalSection(nextAction, info.mType))
{
shouldFinalize = true;
}
Get<Server>().mProxyQueries.Dequeue(query);
info.RemoveFrom(query);
response.InitFrom(query, info);
if ((response.*aAppender)(aResult) != kErrorNone)
{
response.SetResponseCode(Header::kResponseServerFailure);
shouldFinalize = true;
}
if (shouldFinalize)
{
response.Send(info.mMessageInfo);
continue;
}
// The `query` is not yet finished and we need to perform
// the `nextAction` for it.
// Reinitialize `response` as a `ProxyQuey` by updating
// and appending `info` to it after the newly appended
// records from `aResult` and saving the `mHeader`.
info.mOffsets = response.mOffsets;
info.mAction = nextAction;
response.mMessage->Write(0, response.mHeader);
if (response.mMessage->Append(info) != kErrorNone)
{
response.SetResponseCode(Header::kResponseServerFailure);
response.Send(info.mMessageInfo);
continue;
}
// Take back ownership of `response.mMessage` as we still
// treat it as a `ProxyQuery`.
response.mMessage.Release();
// We place the `query` in a separate list and add it back to
// the main `mProxyQueries` list after we are done with the
// current iteration. This ensures that other entries in the
// `mProxyQueries` list are not updated or removed due to the
// DNS-SD platform callback being invoked immediately when we
// potentially start a browser or resolver to perform the
// `nextAction` for `query`.
nextActionQueries.Enqueue(query);
}
for (ProxyQuery &query : nextActionQueries)
{
nextActionQueries.Dequeue(query);
info.ReadFrom(query);
nextAction = info.mAction;
info.mAction = kNoAction;
info.UpdateIn(query);
Get<Server>().mProxyQueries.Enqueue(query);
Perform(nextAction, query, info);
}
}
bool Server::DiscoveryProxy::IsActionForAdditionalSection(ProxyAction aAction, QueryType aQueryType)
{
bool isForAddnlSection = false;
switch (aAction)
{
case kResolvingSrv:
VerifyOrExit((aQueryType == kSrvQuery) || (aQueryType == kSrvTxtQuery));
break;
case kResolvingTxt:
VerifyOrExit((aQueryType == kTxtQuery) || (aQueryType == kSrvTxtQuery));
break;
case kResolvingIp6Address:
VerifyOrExit(aQueryType == kAaaaQuery);
break;
case kNoAction:
case kBrowsing:
ExitNow();
}
isForAddnlSection = true;
exit:
return isForAddnlSection;
}
Error Server::Response::AppendPtrRecord(const ProxyResult &aResult)
{
const Dnssd::BrowseResult *browseResult = aResult.mBrowseResult;
mSection = kAnswerSection;
return AppendPtrRecord(browseResult->mServiceInstance, browseResult->mTtl);
}
Error Server::Response::AppendSrvRecord(const ProxyResult &aResult)
{
const Dnssd::SrvResult *srvResult = aResult.mSrvResult;
Name::Buffer fullHostName;
mSection = ((mType == kSrvQuery) || (mType == kSrvTxtQuery)) ? kAnswerSection : kAdditionalDataSection;
ConstructFullName(srvResult->mHostName, fullHostName);
return AppendSrvRecord(fullHostName, srvResult->mTtl, srvResult->mPriority, srvResult->mWeight, srvResult->mPort);
}
Error Server::Response::AppendTxtRecord(const ProxyResult &aResult)
{
const Dnssd::TxtResult *txtResult = aResult.mTxtResult;
mSection = ((mType == kTxtQuery) || (mType == kSrvTxtQuery)) ? kAnswerSection : kAdditionalDataSection;
return AppendTxtRecord(txtResult->mTxtData, txtResult->mTxtDataLength, txtResult->mTtl);
}
Error Server::Response::AppendHostAddresses(const ProxyResult &aResult)
{
Error error = kErrorNone;
const Dnssd::AddressResult *addrResult = aResult.mAddressResult;
mSection = (mType == kAaaaQuery) ? kAnswerSection : kAdditionalDataSection;
for (uint16_t index = 0; index < addrResult->mAddressesLength; index++)
{
const Dnssd::AddressAndTtl &entry = addrResult->mAddresses[index];
const Ip6::Address &address = AsCoreType(&entry.mAddress);
if (entry.mTtl == 0)
{
continue;
}
if (!IsProxyAddressValid(address))
{
continue;
}
SuccessOrExit(error = AppendAaaaRecord(address, entry.mTtl));
}
exit:
return error;
}
bool Server::IsProxyAddressValid(const Ip6::Address &aAddress)
{
return !aAddress.IsLinkLocal() && !aAddress.IsMulticast() && !aAddress.IsUnspecified() && !aAddress.IsLoopback();
}
#endif // OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
} // namespace ServiceDiscovery
} // namespace Dns
} // namespace ot
+149 -5
View File
@@ -33,8 +33,20 @@
#if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
#if !OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE && !OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
#error "OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE requires either PLATFORM_DNSSD_ENABLE or MULTICAST_DNS_ENABLE"
#endif
#if !OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#error "OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE requires OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE"
#endif
#endif // OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
#include <openthread/dnssd_server.h>
#include "border_router/infra_if.hpp"
#include "common/as_core_type.hpp"
#include "common/callback.hpp"
#include "common/message.hpp"
@@ -42,6 +54,7 @@
#include "common/owned_ptr.hpp"
#include "common/timer.hpp"
#include "net/dns_types.hpp"
#include "net/dnssd.hpp"
#include "net/ip6.hpp"
#include "net/netif.hpp"
#include "net/srp_server.hpp"
@@ -71,6 +84,10 @@ namespace ServiceDiscovery {
class Server : public InstanceLocator, private NonCopyable
{
friend class Srp::Server;
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
friend class ot::Dnssd;
friend class ot::BorderRouter::InfraIf;
#endif
public:
/**
@@ -316,6 +333,17 @@ private:
kAdditionalDataSection,
};
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
enum ProxyAction : uint8_t
{
kNoAction,
kBrowsing,
kResolvingSrv,
kResolvingTxt,
kResolvingIp6Address,
};
#endif
struct Request
{
ResponseCode ParseQuestions(uint8_t aTestMode);
@@ -336,6 +364,21 @@ private:
uint16_t mHostName;
};
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
union ProxyResult
{
explicit ProxyResult(const Dnssd::BrowseResult &aBrowseResult) { mBrowseResult = &aBrowseResult; }
explicit ProxyResult(const Dnssd::SrvResult &aSrvResult) { mSrvResult = &aSrvResult; }
explicit ProxyResult(const Dnssd::TxtResult &aTxtResult) { mTxtResult = &aTxtResult; }
explicit ProxyResult(const Dnssd::AddressResult &aAddressResult) { mAddressResult = &aAddressResult; }
const Dnssd::BrowseResult *mBrowseResult;
const Dnssd::SrvResult *mSrvResult;
const Dnssd::TxtResult *mTxtResult;
const Dnssd::AddressResult *mAddressResult;
};
#endif
class Response : public InstanceLocator, private NonCopyable
{
public:
@@ -360,6 +403,7 @@ private:
Error AppendHostAddresses(const HostInfo &aHostInfo);
Error AppendHostAddresses(const ServiceInstanceInfo &aInstanceInfo);
Error AppendHostAddresses(const Ip6::Address *aAddrs, uint16_t aAddrsLength, uint32_t aTtl);
Error AppendAaaaRecord(const Ip6::Address &aAddress, uint32_t aTtl);
void UpdateRecordLength(ResourceRecord &aRecord, uint16_t aOffset);
void IncResourceRecordCount(void);
void Send(const Ip6::MessageInfo &aMessageInfo);
@@ -373,6 +417,14 @@ private:
Error AppendTxtRecord(const Srp::Server::Service &aService);
Error AppendHostAddresses(const Srp::Server::Host &aHost);
#endif
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
Error AppendPtrRecord(const ProxyResult &aResult);
Error AppendSrvRecord(const ProxyResult &aResult);
Error AppendTxtRecord(const ProxyResult &aResult);
Error AppendHostAddresses(const ProxyResult &aResult);
#endif
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
void Log(void) const;
static const char *QueryTypeToString(QueryType aType);
@@ -395,18 +447,106 @@ private:
Ip6::MessageInfo mMessageInfo;
TimeMilli mExpireTime;
NameOffsets mOffsets;
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
ProxyAction mAction;
#endif
};
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
class DiscoveryProxy : public InstanceLocator, private NonCopyable
{
friend ot::Dnssd;
public:
explicit DiscoveryProxy(Instance &aInstance);
bool IsRunning(void) const { return mIsRunning; }
void UpdateState(void);
void Start(void);
void Stop(void);
void Resolve(ProxyQuery &aQuery, ProxyQueryInfo &aInfo);
void CancelAction(ProxyQuery &aQuery, ProxyQueryInfo &aInfo);
private:
enum Command : uint8_t
{
kStart,
kStop,
};
typedef Error (Response::*ResponseAppender)(const ProxyResult &aResult);
void Perform(ProxyAction aAction, ProxyQuery &aQuery, ProxyQueryInfo &aInfo);
void ReadNameFor(ProxyAction aAction, ProxyQuery &aQuery, ProxyQueryInfo &aInfo, Name::Buffer &aName) const;
bool HasActive(ProxyAction aAction, const Name::Buffer &aName) const;
bool QueryMatches(const ProxyQuery &aQuery,
const ProxyQueryInfo &aInfo,
ProxyAction aAction,
const Name::Buffer &aName) const;
void UpdateProxy(Command aCommand,
ProxyAction aAction,
const ProxyQuery &aQuery,
const ProxyQueryInfo &aInfo,
Name::Buffer &aName);
void StartOrStopBrowser(Command aCommand, Name::Buffer &aServiceName);
void StartOrStopSrvResolver(Command aCommand, const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo);
void StartOrStopTxtResolver(Command aCommand, const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo);
void StartOrStopIp6Resolver(Command aCommand, Name::Buffer &aHostName);
static void HandleBrowseResult(otInstance *aInstance, const otPlatDnssdBrowseResult *aResult);
static void HandleSrvResult(otInstance *aInstance, const otPlatDnssdSrvResult *aResult);
static void HandleTxtResult(otInstance *aInstance, const otPlatDnssdTxtResult *aResult);
static void HandleIp6AddressResult(otInstance *aInstance, const otPlatDnssdAddressResult *aResult);
void HandleBrowseResult(const Dnssd::BrowseResult &aResult);
void HandleSrvResult(const Dnssd::SrvResult &aResult);
void HandleTxtResult(const Dnssd::TxtResult &aResult);
void HandleIp6AddressResult(const Dnssd::AddressResult &aResult);
void HandleResult(ProxyAction aAction,
const Name::Buffer &aName,
ResponseAppender aAppender,
const ProxyResult &aResult);
static bool IsActionForAdditionalSection(ProxyAction aAction, QueryType aQueryType);
bool mIsRunning;
};
#endif
bool IsRunning(void) const { return mSocket.IsBound(); }
static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void ProcessQuery(Request &aRequest);
void ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessageInfo);
void RemoveQueryAndPrepareResponse(ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Response &aResponse);
void Finalize(ProxyQuery &aQuery, ResponseCode aResponseCode);
static void ReadQueryName(const Message &aQuery, Name::Buffer &aName);
static bool QueryNameMatches(const Message &aQuery, const char *aName);
void ResolveByProxy(Response &aResponse, const Ip6::MessageInfo &aMessageInfo);
void RemoveQueryAndPrepareResponse(ProxyQuery &aQuery, ProxyQueryInfo &aInfo, Response &aResponse);
void Finalize(ProxyQuery &aQuery, ResponseCode aResponseCode);
static void ReadQueryName(const Message &aQuery, Name::Buffer &aName);
static bool QueryNameMatches(const Message &aQuery, const char *aName);
static void ReadQueryInstanceName(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Name::Buffer &aName);
static void ReadQueryInstanceName(const ProxyQuery &aQuery,
const ProxyQueryInfo &aInfo,
Name::LabelBuffer &aInstanceLabel,
Name::Buffer &aServiceType);
static bool QueryInstanceNameMatches(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, const char *aName);
static void ReadQueryHostName(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, Name::Buffer &aName);
static bool QueryHostNameMatches(const ProxyQuery &aQuery, const ProxyQueryInfo &aInfo, const char *aName);
static Error StripDomainName(const char *aFullName, Name::Buffer &aLabels);
static Error StripDomainName(Name::Buffer &aName);
static void ConstructFullName(const char *aLabels, Name::Buffer &aFullName);
static void ConstructFullInstanceName(const char *aInstanceLabel,
const char *aServiceType,
Name::Buffer &aFullName);
static void ConstructFullServiceSubTypeName(const char *aServiceType,
const char *aSubTypeLabel,
Name::Buffer &aFullName);
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
void HandleInfraIfStateChanged(void) { mDiscoveryProxy.UpdateState(); }
void HandleDnssdPlatformStateChange(void) { mDiscoveryProxy.UpdateState(); }
static bool IsProxyAddressValid(const Ip6::Address &aAddress);
#endif
#if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
static bool ShouldForwardToUpstream(const Request &aRequest);
@@ -434,6 +574,10 @@ private:
Callback<SubscribeCallback> mQuerySubscribe;
Callback<UnsubscribeCallback> mQueryUnsubscribe;
#if OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE
DiscoveryProxy mDiscoveryProxy;
#endif
#if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
bool mEnableUpstreamQuery;
UpstreamQueryTransaction mUpstreamQueryTransactions[kMaxConcurrentUpstreamQueries];
@@ -76,6 +76,8 @@
#define OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#define OPENTHREAD_CONFIG_DNSSD_DISCOVERY_PROXY_ENABLE OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#define OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE 1
#define OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE 1
+1
View File
@@ -176,6 +176,7 @@ ot_unit_test(data)
ot_unit_test(dataset)
ot_unit_test(dns)
ot_unit_test(dns_client)
ot_unit_test(dnssd_discovery_proxy)
ot_unit_test(dso)
ot_unit_test(ecdsa)
ot_unit_test(flash)
File diff suppressed because it is too large Load Diff
+60
View File
@@ -877,6 +877,66 @@ OT_TOOL_WEAK void otPlatDnssdUnregisterKey(otInstance *aInstance
OT_UNUSED_VARIABLE(aCallback);
}
OT_TOOL_WEAK void otPlatDnssdStartBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aBrowser);
}
OT_TOOL_WEAK void otPlatDnssdStopBrowser(otInstance *aInstance, const otPlatDnssdBrowser *aBrowser)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aBrowser);
}
OT_TOOL_WEAK void otPlatDnssdStartSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
OT_TOOL_WEAK void otPlatDnssdStopSrvResolver(otInstance *aInstance, const otPlatDnssdSrvResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
OT_TOOL_WEAK void otPlatDnssdStartTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
OT_TOOL_WEAK void otPlatDnssdStopTxtResolver(otInstance *aInstance, const otPlatDnssdTxtResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
OT_TOOL_WEAK void otPlatDnssdStartIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
OT_TOOL_WEAK void otPlatDnssdStopIp6AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
OT_TOOL_WEAK void otPlatDnssdStartIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
OT_TOOL_WEAK void otPlatDnssdStopIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aResolver);
}
#endif // OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
#if OPENTHREAD_CONFIG_PLATFORM_LOG_CRASH_DUMP_ENABLE