Skip to content

Commit 20aefc2

Browse files
authored
[dnssd] support generic record queries via discovery proxy and SRP (openthread#11357)
This commit enhances the OpenThread DNSSD name server/resolver and its native Discovery Proxy to support queries for arbitrary record types. To enable this, a new set of `otPlatDnssd` APIs are introduced for generic `RecordQuerier`. These APIs mirror the existing APIs in the OpenThread native mDNS module, allowing direct use of the native mDNS implementation. The discovery proxy implementation is updated to start and stop the mDNS `RecordQuerier` when receiving a query for an arbitrary record type, passing the first response record back to the client. The unit tests `test_dnssd_discovery_proxy` and `test_dns_client` are updated to cover all the newly added behaviors in discovery proxy.
1 parent 4be7e8b commit 20aefc2

18 files changed

Lines changed: 1378 additions & 239 deletions

File tree

examples/platforms/simulation/dnssd.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,16 @@ void otPlatDnssdStopIp4AddressResolver(otInstance *aInstance, const otPlatDnssdA
164164
OT_UNUSED_VARIABLE(aResolver);
165165
}
166166

167+
void otPlatDnssdStartRecordQuerier(otInstance *aInstance, const otPlatDnssdRecordQuerier *aQuerier)
168+
{
169+
OT_UNUSED_VARIABLE(aInstance);
170+
OT_UNUSED_VARIABLE(aQuerier);
171+
}
172+
173+
void otPlatDnssdStopRecordQuerier(otInstance *aInstance, const otPlatDnssdRecordQuerier *aQuerier)
174+
{
175+
OT_UNUSED_VARIABLE(aInstance);
176+
OT_UNUSED_VARIABLE(aQuerier);
177+
}
178+
167179
#endif // OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE && OPENTHREAD_SIMULATION_IMPLEMENT_DNSSD

include/openthread/instance.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ extern "C" {
5252
*
5353
* @note This number versions both OpenThread platform and user APIs.
5454
*/
55-
#define OPENTHREAD_API_VERSION (500)
55+
#define OPENTHREAD_API_VERSION (501)
5656

5757
/**
5858
* @addtogroup api-instance

include/openthread/mdns.h

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -612,36 +612,17 @@ typedef otPlatDnssdAddressResult otMdnsAddressResult;
612612
/**
613613
* Represents a record query result.
614614
*/
615-
typedef struct otMdnsRecordResult
616-
{
617-
const char *mFirstLabel; ///< The first label of the name to be queried.
618-
const char *mNextLabels; ///< The rest of the name labels. Does not include domain name. Can be NULL.
619-
uint16_t mRecordType; ///< The record type.
620-
const uint8_t *mRecordData; ///< The record data bytes.
621-
uint16_t mRecordDataLength; ///< Number of bytes in record data.
622-
uint32_t mTtl; ///< TTL in seconds. Zero TTL indicates removal the data.
623-
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
624-
} otMdnsRecordResult;
615+
typedef otPlatDnssdRecordResult otMdnsRecordResult;
625616

626617
/**
627618
* Represents the callback function used to report a record querier result.
628-
*
629-
* @param[in] aInstance The OpenThread instance.
630-
* @param[in] aResult The record querier result.
631619
*/
632-
typedef void (*otMdnsRecordCallback)(otInstance *aInstance, const otMdnsRecordResult *aResult);
620+
typedef otPlatDnssdRecordCallback otMdnsRecordCallback;
633621

634622
/**
635623
* Represents a record querier.
636624
*/
637-
typedef struct otMdnsRecordQuerier
638-
{
639-
const char *mFirstLabel; ///< The first label of the name to be queried. MUST NOT be NULL.
640-
const char *mNextLabels; ///< The rest of name labels, excluding domain name. Can be NULL.
641-
uint16_t mRecordType; ///< The record type to query.
642-
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
643-
otMdnsRecordCallback mCallback; ///< The callback to report result.
644-
} otMdnsRecordQuerier;
625+
typedef otPlatDnssdRecordQuerier otMdnsRecordQuerier;
645626

646627
/**
647628
* Starts a service browser.

include/openthread/platform/dnssd.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,40 @@ typedef struct otPlatDnssdAddressResolver
539539
otPlatDnssdAddressCallback mCallback; ///< The callback to report result.
540540
} otPlatDnssdAddressResolver;
541541

542+
/**
543+
* Represents a record query result.
544+
*/
545+
typedef struct otPlatDnssdRecordResult
546+
{
547+
const char *mFirstLabel; ///< The first label of the name to be queried.
548+
const char *mNextLabels; ///< The rest of the name labels. Does not include domain name. Can be NULL.
549+
uint16_t mRecordType; ///< The record type.
550+
const uint8_t *mRecordData; ///< The record data bytes.
551+
uint16_t mRecordDataLength; ///< Number of bytes in record data.
552+
uint32_t mTtl; ///< TTL in seconds. Zero TTL indicates removal the data.
553+
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
554+
} otPlatDnssdRecordResult;
555+
556+
/**
557+
* Represents the callback function used to report a record querier result.
558+
*
559+
* @param[in] aInstance The OpenThread instance.
560+
* @param[in] aResult The record querier result.
561+
*/
562+
typedef void (*otPlatDnssdRecordCallback)(otInstance *aInstance, const otPlatDnssdRecordResult *aResult);
563+
564+
/**
565+
* Represents a record querier.
566+
*/
567+
typedef struct otPlatDnssdRecordQuerier
568+
{
569+
const char *mFirstLabel; ///< The first label of the name to be queried. MUST NOT be NULL.
570+
const char *mNextLabels; ///< The rest of name labels, excluding domain name. Can be NULL.
571+
uint16_t mRecordType; ///< The record type to query.
572+
uint32_t mInfraIfIndex; ///< The infrastructure network interface index.
573+
otPlatDnssdRecordCallback mCallback; ///< The callback to report result.
574+
} otPlatDnssdRecordQuerier;
575+
542576
/**
543577
* Starts a service browser.
544578
*
@@ -718,6 +752,46 @@ void otPlatDnssdStartIp4AddressResolver(otInstance *aInstance, const otPlatDnssd
718752
*/
719753
void otPlatDnssdStopIp4AddressResolver(otInstance *aInstance, const otPlatDnssdAddressResolver *aResolver);
720754

755+
/**
756+
* Starts a record querier.
757+
*
758+
* Initiates a continuous query for a given `mRecordType` as specified in @p aQuerier. The queried name is specified
759+
* by the combination of `mFirstLabel` and `mNextLabels` (optional rest of the labels) in @p aQuerier. The
760+
* `mFirstLabel` is always non-NULL but `mNextLabels` can be `NULL` if there are no other labels. The `mNextLabels
761+
* does not include the domain name. The reason for a separate first label is to allow it to include a dot `.`
762+
* character (as allowed for service instance labels).
763+
*
764+
* Discovered results should be reported through the `mCallback` function in @p aQuerier, providing the raw record
765+
* data bytes. A removed record data is indicated with a TTL value of zero. The callback may be invoked immediately
766+
* with cached information (if available) and potentially before this function returns. When cached results are used,
767+
* the reported TTL value should reflect the original TTL from the last received response.
768+
*
769+
* Multiple querier instances can be started for the same name, provided they use different callback functions.
770+
*
771+
* OpenThread will only use a record querier for types other than PTR, SRV, TXT, A, and AAAA. For those, specific
772+
* browsers or resolvers are used. The platform implementation, therefore, can choose to restrict its implementation.
773+
*
774+
* The @p aQuerier and all its contained information (strings) are only valid during this call. The platform MUST save
775+
* a copy of the information if it wants to retain the information after returning from this function.
776+
*
777+
* @param[in] aInstance The OpenThread instance.
778+
* @param[in] aQuerier The record querier to be started.
779+
*/
780+
void otPlatDnssdStartRecordQuerier(otInstance *aInstance, const otPlatDnssdRecordQuerier *aQuerier);
781+
782+
/**
783+
* Stops a record querier.
784+
*
785+
* No action is performed if no matching querier with the same name, record type and callback is currently active.
786+
*
787+
* The @p aQuerier and all its contained information (strings) are only valid during this call. The platform MUST save
788+
* a copy of the information if it wants to retain the information after returning from this function.
789+
*
790+
* @param[in] aInstance The OpenThread instance.
791+
* @param[in] aQuerier The record querier to be stopped.
792+
*/
793+
void otPlatDnssdStopRecordQuerier(otInstance *aInstance, const otPlatDnssdRecordQuerier *aQuerier);
794+
721795
/**
722796
* @}
723797
*/

src/core/net/dns_types.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,32 @@ Error ResourceRecord::DecompressRecordData(const Message &aMessage, uint16_t aOf
11311131
return error;
11321132
}
11331133

1134+
ResourceRecord::TypeInfoString ResourceRecord::TypeToString(uint16_t aRecordType)
1135+
{
1136+
static constexpr Stringify::Entry kRecordTypeTable[] = {
1137+
{kTypeA, "A"}, {kTypeNs, "NS"}, {kTypeCname, "CNAME"}, {kTypeSoa, "SOA"}, {kTypePtr, "PTR"},
1138+
{kTypeMx, "MX"}, {kTypeTxt, "TXT"}, {kTypeRp, "RP"}, {kTypeAfsdb, "AFSDB"}, {kTypeRt, "RT"},
1139+
{kTypeSig, "SIG"}, {kTypeKey, "KEY"}, {kTypePx, "PX"}, {kTypeAaaa, "AAAA"}, {kTypeSrv, "SRV"},
1140+
{kTypeKx, "KX"}, {kTypeDname, "DNAME"}, {kTypeOpt, "OPT"}, {kTypeNsec, "NSEC"}, {kTypeAny, "ANY"},
1141+
};
1142+
1143+
static_assert(Stringify::IsSorted(kRecordTypeTable), "kRecordTypeTable is not sorted");
1144+
1145+
TypeInfoString string;
1146+
const char *lookupResult = Stringify::Lookup(aRecordType, kRecordTypeTable, nullptr);
1147+
1148+
if (lookupResult != nullptr)
1149+
{
1150+
string.Append("%s", lookupResult);
1151+
}
1152+
else
1153+
{
1154+
string.Append("RR:%u", aRecordType);
1155+
}
1156+
1157+
return string;
1158+
}
1159+
11341160
void TxtEntry::Iterator::Init(const uint8_t *aTxtData, uint16_t aTxtDataLength)
11351161
{
11361162
SetTxtData(aTxtData);

src/core/net/dns_types.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include "common/equatable.hpp"
4747
#include "common/message.hpp"
4848
#include "common/owned_ptr.hpp"
49+
#include "common/string.hpp"
4950
#include "crypto/ecdsa.hpp"
5051
#include "net/ip4_types.hpp"
5152
#include "net/ip6_address.hpp"
@@ -1293,6 +1294,10 @@ class ResourceRecord
12931294
static constexpr uint16_t kClassNone = 254; ///< Class code None (NONE) - RFC 2136.
12941295
static constexpr uint16_t kClassAny = 255; ///< Class code Any (ANY).
12951296

1297+
static constexpr uint16_t kTypeStringSize = 17; ///< Size of `TypeInfoString`.
1298+
1299+
typedef String<kTypeStringSize> TypeInfoString; /// A string to represent a resource record type (human-readable).
1300+
12961301
/**
12971302
* Initializes the resource record by setting its type and class.
12981303
*
@@ -1545,6 +1550,15 @@ class ResourceRecord
15451550
*/
15461551
static Error DecompressRecordData(const Message &aMessage, uint16_t aOffset, OwnedPtr<Message> &aDataMsg);
15471552

1553+
/**
1554+
* Returns a human-readable string representation of a given resource record type.
1555+
*
1556+
* @param[in] aRecordType The resource record type to convert.
1557+
*
1558+
* @returns human-readable string representation of a given resource record type.
1559+
*/
1560+
static TypeInfoString TypeToString(uint16_t aRecordType);
1561+
15481562
protected:
15491563
Error ReadName(const Message &aMessage,
15501564
uint16_t &aOffset,

src/core/net/dnssd.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,50 @@ void Dnssd::StopIp4AddressResolver(const AddressResolver &aResolver)
473473
return;
474474
}
475475

476+
void Dnssd::StartRecordQuerier(const RecordQuerier &aQuerier)
477+
{
478+
VerifyOrExit(IsReady());
479+
480+
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION
481+
if (mUseNativeMdns)
482+
#endif
483+
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
484+
{
485+
IgnoreError(Get<Dns::Multicast::Core>().StartRecordQuerier(aQuerier));
486+
ExitNow();
487+
}
488+
#endif
489+
490+
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
491+
otPlatDnssdStartRecordQuerier(&GetInstance(), &aQuerier);
492+
#endif
493+
494+
exit:
495+
return;
496+
}
497+
498+
void Dnssd::StopRecordQuerier(const RecordQuerier &aQuerier)
499+
{
500+
VerifyOrExit(IsReady());
501+
502+
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ALLOW_RUN_TIME_SELECTION
503+
if (mUseNativeMdns)
504+
#endif
505+
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
506+
{
507+
IgnoreError(Get<Dns::Multicast::Core>().StopRecordQuerier(aQuerier));
508+
ExitNow();
509+
}
510+
#endif
511+
512+
#if OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
513+
otPlatDnssdStopRecordQuerier(&GetInstance(), &aQuerier);
514+
#endif
515+
516+
exit:
517+
return;
518+
}
519+
476520
void Dnssd::HandleStateChange(void)
477521
{
478522
#if OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE

src/core/net/dnssd.hpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,14 @@ class Dnssd : public InstanceLocator, private NonCopyable
9393
typedef otPlatDnssdBrowseCallback BrowseCallback; ///< Browser callback.
9494
typedef otPlatDnssdSrvCallback SrvCallback; ///< SRV callback.
9595
typedef otPlatDnssdTxtCallback TxtCallback; ///< TXT callback.
96-
typedef otPlatDnssdAddressCallback AddressCallback; ///< Address callback
96+
typedef otPlatDnssdAddressCallback AddressCallback; ///< Address callback.
97+
typedef otPlatDnssdRecordCallback RecordCallback; ///< Record callback.
9798
typedef otPlatDnssdBrowseResult BrowseResult; ///< Browser result.
9899
typedef otPlatDnssdSrvResult SrvResult; ///< SRV result.
99100
typedef otPlatDnssdTxtResult TxtResult; ///< TXT result.
100101
typedef otPlatDnssdAddressResult AddressResult; ///< Address result.
101102
typedef otPlatDnssdAddressAndTtl AddressAndTtl; ///< Address and TTL.
103+
typedef otPlatDnssdRecordResult RecordResult; ///< Record result.
102104

103105
class Host : public otPlatDnssdHost, public Clearable<Host> ///< Host information.
104106
{
@@ -128,6 +130,10 @@ class Dnssd : public InstanceLocator, private NonCopyable
128130
{
129131
};
130132

133+
class RecordQuerier : public otPlatDnssdRecordQuerier, public Clearable<RecordQuerier> ///< Record querier.
134+
{
135+
};
136+
131137
/**
132138
* Represents a range of `RequestId` values.
133139
*
@@ -381,6 +387,26 @@ class Dnssd : public InstanceLocator, private NonCopyable
381387
*/
382388
void StopIp4AddressResolver(const AddressResolver &aResolver);
383389

390+
/**
391+
* Starts a record querier.
392+
*
393+
* Refer to the documentation for `otPlatDnssdStartRecordQuerier()` for a more detailed description of the
394+
* behavior of this method.
395+
*
396+
* @param[in] aQuerier The querier to be started.
397+
*/
398+
void StartRecordQuerier(const RecordQuerier &aQuerier);
399+
400+
/**
401+
* Stops a record querier.
402+
*
403+
* Refer to the documentation for `otPlatDnssdStopRecordQuerier()` for a more detailed description of the
404+
* behavior of this method.
405+
*
406+
* @param[in] aQuerier The querier to stop.
407+
*/
408+
void StopRecordQuerier(const RecordQuerier &aQuerier);
409+
384410
#if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
385411
/**
386412
* Handles native mDNS state change.

0 commit comments

Comments
 (0)