1 /*
2  *  Copyright (c) 2024, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <openthread/config.h>
30 
31 #include "test_platform.h"
32 #include "test_util.hpp"
33 
34 #include "common/arg_macros.hpp"
35 #include "common/array.hpp"
36 #include "common/as_core_type.hpp"
37 #include "common/num_utils.hpp"
38 #include "common/owning_list.hpp"
39 #include "common/string.hpp"
40 #include "common/time.hpp"
41 #include "instance/instance.hpp"
42 #include "net/dns_dso.hpp"
43 #include "net/mdns.hpp"
44 
45 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
46 
47 namespace ot {
48 namespace Dns {
49 namespace Multicast {
50 
51 #define ENABLE_TEST_LOG 1 // Enable to get logs from unit test.
52 
53 // Logs a message and adds current time (sNow) as "<hours>:<min>:<secs>.<msec>"
54 #if ENABLE_TEST_LOG
55 #define Log(...)                                                                                         \
56     printf("%02u:%02u:%02u.%03u " OT_FIRST_ARG(__VA_ARGS__) "\n", (sNow / 3600000), (sNow / 60000) % 60, \
57            (sNow / 1000) % 60, sNow % 1000 OT_REST_ARGS(__VA_ARGS__))
58 #else
59 #define Log(...)
60 #endif
61 
62 //---------------------------------------------------------------------------------------------------------------------
63 // Constants
64 
65 static constexpr uint16_t kClassQueryUnicastFlag  = (1U << 15);
66 static constexpr uint16_t kClassCacheFlushFlag    = (1U << 15);
67 static constexpr uint16_t kClassMask              = 0x7fff;
68 static constexpr uint16_t kStringSize             = 300;
69 static constexpr uint16_t kMaxDataSize            = 400;
70 static constexpr uint16_t kNumAnnounces           = 3;
71 static constexpr uint16_t kNumInitalQueries       = 3;
72 static constexpr uint16_t kNumRefreshQueries      = 4;
73 static constexpr bool     kCacheFlush             = true;
74 static constexpr uint16_t kMdnsPort               = 5353;
75 static constexpr uint16_t kEphemeralPort          = 49152;
76 static constexpr uint16_t kLegacyUnicastMessageId = 1;
77 static constexpr uint16_t kMaxLegacyUnicastTtl    = 10;
78 static constexpr uint32_t kInfraIfIndex           = 1;
79 
80 static const char kDeviceIp6Address[] = "fd01::1";
81 
82 class DnsMessage;
83 
84 //---------------------------------------------------------------------------------------------------------------------
85 // Variables
86 
87 static Instance *sInstance;
88 
89 static uint32_t sNow = 0;
90 static uint32_t sAlarmTime;
91 static bool     sAlarmOn = false;
92 
93 OwningList<DnsMessage> sDnsMessages;
94 uint32_t               sInfraIfIndex;
95 
96 //---------------------------------------------------------------------------------------------------------------------
97 // Prototypes
98 
99 static const char *RecordTypeToString(uint16_t aType);
100 
101 //---------------------------------------------------------------------------------------------------------------------
102 // Types
103 
104 template <typename Type> class Allocatable
105 {
106 public:
Allocate(void)107     static Type *Allocate(void)
108     {
109         void *buf = calloc(1, sizeof(Type));
110 
111         VerifyOrQuit(buf != nullptr);
112         return new (buf) Type();
113     }
114 
Free(void)115     void Free(void)
116     {
117         static_cast<Type *>(this)->~Type();
118         free(this);
119     }
120 };
121 
122 struct DnsName
123 {
124     Name::Buffer mName;
125 
ParseFromot::Dns::Multicast::DnsName126     void ParseFrom(const Message &aMessage, uint16_t &aOffset)
127     {
128         SuccessOrQuit(Name::ReadName(aMessage, aOffset, mName));
129     }
130 
CopyFromot::Dns::Multicast::DnsName131     void CopyFrom(const char *aName)
132     {
133         if (aName == nullptr)
134         {
135             mName[0] = '\0';
136         }
137         else
138         {
139             uint16_t len = StringLength(aName, sizeof(mName));
140 
141             VerifyOrQuit(len < sizeof(mName));
142             memcpy(mName, aName, len + 1);
143         }
144     }
145 
AsCStringot::Dns::Multicast::DnsName146     const char *AsCString(void) const { return mName; }
Matchesot::Dns::Multicast::DnsName147     bool        Matches(const char *aName) const { return StringMatch(mName, aName, kStringCaseInsensitiveMatch); }
148 };
149 
150 typedef String<Name::kMaxNameSize> DnsNameString;
151 
152 struct AddrAndTtl
153 {
operator ==ot::Dns::Multicast::AddrAndTtl154     bool operator==(const AddrAndTtl &aOther) const { return (mTtl == aOther.mTtl) && (mAddress == aOther.mAddress); }
155 
156     Ip6::Address mAddress;
157     uint32_t     mTtl;
158 };
159 
160 struct DnsQuestion : public Allocatable<DnsQuestion>, public LinkedListEntry<DnsQuestion>
161 {
162     DnsQuestion *mNext;
163     DnsName      mName;
164     uint16_t     mType;
165     uint16_t     mClass;
166     bool         mUnicastResponse;
167 
ParseFromot::Dns::Multicast::DnsQuestion168     void ParseFrom(const Message &aMessage, uint16_t &aOffset)
169     {
170         Question question;
171 
172         mName.ParseFrom(aMessage, aOffset);
173         SuccessOrQuit(aMessage.Read(aOffset, question));
174         aOffset += sizeof(Question);
175 
176         mNext            = nullptr;
177         mType            = question.GetType();
178         mClass           = question.GetClass() & kClassMask;
179         mUnicastResponse = question.GetClass() & kClassQueryUnicastFlag;
180 
181         Log("      %s %s %s class:%u", mName.AsCString(), RecordTypeToString(mType), mUnicastResponse ? "QU" : "QM",
182             mClass);
183     }
184 
Matchesot::Dns::Multicast::DnsQuestion185     bool Matches(const char *aName) const { return mName.Matches(aName); }
186 };
187 
188 struct DnsQuestions : public OwningList<DnsQuestion>
189 {
Containsot::Dns::Multicast::DnsQuestions190     bool Contains(uint16_t aRrType, const DnsNameString &aFullName, bool aUnicastResponse = false) const
191     {
192         bool               contains = false;
193         const DnsQuestion *question = FindMatching(aFullName.AsCString());
194 
195         VerifyOrExit(question != nullptr);
196         VerifyOrExit(question->mType == aRrType);
197         VerifyOrExit(question->mClass == ResourceRecord::kClassInternet);
198         VerifyOrExit(question->mUnicastResponse == aUnicastResponse);
199         contains = true;
200 
201     exit:
202         return contains;
203     }
204 
Containsot::Dns::Multicast::DnsQuestions205     bool Contains(const DnsNameString &aFullName, bool aUnicastResponse) const
206     {
207         return Contains(ResourceRecord::kTypeAny, aFullName, aUnicastResponse);
208     }
209 };
210 
211 enum TtlCheckMode : uint8_t
212 {
213     kZeroTtl,
214     kNonZeroTtl,
215     kLegacyUnicastTtl,
216 };
217 
218 enum Section : uint8_t
219 {
220     kInAnswerSection,
221     kInAdditionalSection,
222 };
223 
224 struct Data : public ot::Data<kWithUint16Length>
225 {
Dataot::Dns::Multicast::Data226     Data(const void *aBuffer, uint16_t aLength) { Init(aBuffer, aLength); }
227 
Matchesot::Dns::Multicast::Data228     bool Matches(const Array<uint8_t, kMaxDataSize> &aDataArray) const
229     {
230         return (aDataArray.GetLength() == GetLength()) && MatchesBytesIn(aDataArray.GetArrayBuffer());
231     }
232 };
233 
234 struct DnsRecord : public Allocatable<DnsRecord>, public LinkedListEntry<DnsRecord>
235 {
236     struct SrvData
237     {
238         uint16_t mPriority;
239         uint16_t mWeight;
240         uint16_t mPort;
241         DnsName  mHostName;
242     };
243 
244     union RecordData
245     {
RecordData(void)246         RecordData(void) { memset(this, 0, sizeof(*this)); }
247 
248         Ip6::Address                 mIp6Address; // For AAAAA (or A)
249         SrvData                      mSrv;        // For SRV
250         Array<uint8_t, kMaxDataSize> mData;       // For TXT or KEY
251         DnsName                      mPtrName;    // For PTR
252         NsecRecord::TypeBitMap       mNsecBitmap; // For NSEC
253     };
254 
255     DnsRecord *mNext;
256     DnsName    mName;
257     uint16_t   mType;
258     uint16_t   mClass;
259     uint32_t   mTtl;
260     bool       mCacheFlush;
261     RecordData mData;
262 
Matchesot::Dns::Multicast::DnsRecord263     bool Matches(const char *aName) const { return mName.Matches(aName); }
264 
ParseFromot::Dns::Multicast::DnsRecord265     void ParseFrom(const Message &aMessage, uint16_t &aOffset)
266     {
267         String<kStringSize> logStr;
268         ResourceRecord      record;
269         uint16_t            offset;
270 
271         mName.ParseFrom(aMessage, aOffset);
272         SuccessOrQuit(aMessage.Read(aOffset, record));
273         aOffset += sizeof(ResourceRecord);
274 
275         mNext       = nullptr;
276         mType       = record.GetType();
277         mClass      = record.GetClass() & kClassMask;
278         mCacheFlush = record.GetClass() & kClassCacheFlushFlag;
279         mTtl        = record.GetTtl();
280 
281         logStr.Append("%s %s%s cls:%u ttl:%u", mName.AsCString(), RecordTypeToString(mType),
282                       mCacheFlush ? " cache-flush" : "", mClass, mTtl);
283 
284         offset = aOffset;
285 
286         switch (mType)
287         {
288         case ResourceRecord::kTypeAaaa:
289             VerifyOrQuit(record.GetLength() == sizeof(Ip6::Address));
290             SuccessOrQuit(aMessage.Read(offset, mData.mIp6Address));
291             logStr.Append(" %s", mData.mIp6Address.ToString().AsCString());
292             break;
293 
294         case ResourceRecord::kTypeKey:
295         case ResourceRecord::kTypeTxt:
296             VerifyOrQuit(record.GetLength() > 0);
297             VerifyOrQuit(record.GetLength() < kMaxDataSize);
298             mData.mData.SetLength(record.GetLength());
299             SuccessOrQuit(aMessage.Read(offset, mData.mData.GetArrayBuffer(), record.GetLength()));
300             logStr.Append(" data-len:%u", record.GetLength());
301             break;
302 
303         case ResourceRecord::kTypePtr:
304             mData.mPtrName.ParseFrom(aMessage, offset);
305             VerifyOrQuit(offset - aOffset == record.GetLength());
306             logStr.Append(" %s", mData.mPtrName.AsCString());
307             break;
308 
309         case ResourceRecord::kTypeSrv:
310         {
311             SrvRecord srv;
312 
313             offset -= sizeof(ResourceRecord);
314             SuccessOrQuit(aMessage.Read(offset, srv));
315             offset += sizeof(srv);
316             mData.mSrv.mHostName.ParseFrom(aMessage, offset);
317             VerifyOrQuit(offset - aOffset == record.GetLength());
318             mData.mSrv.mPriority = srv.GetPriority();
319             mData.mSrv.mWeight   = srv.GetWeight();
320             mData.mSrv.mPort     = srv.GetPort();
321             logStr.Append(" port:%u w:%u prio:%u host:%s", mData.mSrv.mPort, mData.mSrv.mWeight, mData.mSrv.mPriority,
322                           mData.mSrv.mHostName.AsCString());
323             break;
324         }
325 
326         case ResourceRecord::kTypeNsec:
327         {
328             NsecRecord::TypeBitMap &bitmap = mData.mNsecBitmap;
329 
330             SuccessOrQuit(Name::CompareName(aMessage, offset, mName.AsCString()));
331             SuccessOrQuit(aMessage.Read(offset, &bitmap, NsecRecord::TypeBitMap::kMinSize));
332             VerifyOrQuit(bitmap.GetBlockNumber() == 0);
333             VerifyOrQuit(bitmap.GetBitmapLength() <= NsecRecord::TypeBitMap::kMaxLength);
334             SuccessOrQuit(aMessage.Read(offset, &bitmap, bitmap.GetSize()));
335 
336             offset += bitmap.GetSize();
337             VerifyOrQuit(offset - aOffset == record.GetLength());
338 
339             logStr.Append(" [ ");
340 
341             for (uint16_t type = 0; type < bitmap.GetBitmapLength() * kBitsPerByte; type++)
342             {
343                 if (bitmap.ContainsType(type))
344                 {
345                     logStr.Append("%s ", RecordTypeToString(type));
346                 }
347             }
348 
349             logStr.Append("]");
350             break;
351         }
352 
353         default:
354             break;
355         }
356 
357         Log("      %s", logStr.AsCString());
358 
359         aOffset += record.GetLength();
360     }
361 
MatchesTtlot::Dns::Multicast::DnsRecord362     bool MatchesTtl(TtlCheckMode aTtlCheckMode, uint32_t aTtl) const
363     {
364         bool matches = false;
365 
366         switch (aTtlCheckMode)
367         {
368         case kZeroTtl:
369             VerifyOrExit(mTtl == 0);
370             break;
371         case kNonZeroTtl:
372             if (aTtl > 0)
373             {
374                 VerifyOrQuit(mTtl == aTtl);
375             }
376 
377             VerifyOrExit(mTtl > 0);
378             break;
379         case kLegacyUnicastTtl:
380             VerifyOrQuit(mTtl <= kMaxLegacyUnicastTtl);
381             break;
382         }
383 
384         matches = true;
385 
386     exit:
387         return matches;
388     }
389 };
390 
391 struct DnsRecords : public OwningList<DnsRecord>
392 {
ContainsAaaaot::Dns::Multicast::DnsRecords393     bool ContainsAaaa(const DnsNameString &aFullName,
394                       const Ip6::Address  &aAddress,
395                       bool                 aCacheFlush,
396                       TtlCheckMode         aTtlCheckMode,
397                       uint32_t             aTtl = 0) const
398     {
399         bool contains = false;
400 
401         for (const DnsRecord &record : *this)
402         {
403             if (record.Matches(aFullName.AsCString()) && (record.mType == ResourceRecord::kTypeAaaa) &&
404                 (record.mData.mIp6Address == aAddress))
405             {
406                 VerifyOrExit(record.mClass == ResourceRecord::kClassInternet);
407                 VerifyOrExit(record.mCacheFlush == aCacheFlush);
408                 VerifyOrExit(record.MatchesTtl(aTtlCheckMode, aTtl));
409                 contains = true;
410                 ExitNow();
411             }
412         }
413 
414     exit:
415         return contains;
416     }
417 
ContainsKeyot::Dns::Multicast::DnsRecords418     bool ContainsKey(const DnsNameString &aFullName,
419                      const Data          &aKeyData,
420                      bool                 aCacheFlush,
421                      TtlCheckMode         aTtlCheckMode,
422                      uint32_t             aTtl = 0) const
423     {
424         bool contains = false;
425 
426         for (const DnsRecord &record : *this)
427         {
428             if (record.Matches(aFullName.AsCString()) && (record.mType == ResourceRecord::kTypeKey) &&
429                 aKeyData.Matches(record.mData.mData))
430             {
431                 VerifyOrExit(record.mClass == ResourceRecord::kClassInternet);
432                 VerifyOrExit(record.mCacheFlush == aCacheFlush);
433                 VerifyOrExit(record.MatchesTtl(aTtlCheckMode, aTtl));
434                 contains = true;
435                 ExitNow();
436             }
437         }
438 
439     exit:
440         return contains;
441     }
442 
ContainsSrvot::Dns::Multicast::DnsRecords443     bool ContainsSrv(const DnsNameString &aFullName,
444                      const Core::Service &aService,
445                      bool                 aCacheFlush,
446                      TtlCheckMode         aTtlCheckMode,
447                      uint32_t             aTtl = 0) const
448     {
449         bool          contains = false;
450         DnsNameString hostName;
451 
452         hostName.Append("%s.local.", aService.mHostName);
453 
454         for (const DnsRecord &record : *this)
455         {
456             if (record.Matches(aFullName.AsCString()) && (record.mType == ResourceRecord::kTypeSrv))
457             {
458                 VerifyOrExit(record.mClass == ResourceRecord::kClassInternet);
459                 VerifyOrExit(record.mCacheFlush == aCacheFlush);
460                 VerifyOrExit(record.MatchesTtl(aTtlCheckMode, aTtl));
461                 VerifyOrExit(record.mData.mSrv.mPort == aService.mPort);
462                 VerifyOrExit(record.mData.mSrv.mPriority == aService.mPriority);
463                 VerifyOrExit(record.mData.mSrv.mWeight == aService.mWeight);
464                 VerifyOrExit(record.mData.mSrv.mHostName.Matches(hostName.AsCString()));
465                 contains = true;
466                 ExitNow();
467             }
468         }
469 
470     exit:
471         return contains;
472     }
473 
ContainsTxtot::Dns::Multicast::DnsRecords474     bool ContainsTxt(const DnsNameString &aFullName,
475                      const Core::Service &aService,
476                      bool                 aCacheFlush,
477                      TtlCheckMode         aTtlCheckMode,
478                      uint32_t             aTtl = 0) const
479     {
480         static const uint8_t kEmptyTxtData[1] = {0};
481 
482         bool contains = false;
483         Data txtData(aService.mTxtData, aService.mTxtDataLength);
484 
485         if ((aService.mTxtData == nullptr) || (aService.mTxtDataLength == 0))
486         {
487             txtData.Init(kEmptyTxtData, sizeof(kEmptyTxtData));
488         }
489 
490         for (const DnsRecord &record : *this)
491         {
492             if (record.Matches(aFullName.AsCString()) && (record.mType == ResourceRecord::kTypeTxt) &&
493                 txtData.Matches(record.mData.mData))
494             {
495                 VerifyOrExit(record.mClass == ResourceRecord::kClassInternet);
496                 VerifyOrExit(record.mCacheFlush == aCacheFlush);
497                 VerifyOrExit(record.MatchesTtl(aTtlCheckMode, aTtl));
498                 contains = true;
499                 ExitNow();
500             }
501         }
502 
503     exit:
504         return contains;
505     }
506 
ContainsPtrot::Dns::Multicast::DnsRecords507     bool ContainsPtr(const DnsNameString &aFullName,
508                      const DnsNameString &aPtrName,
509                      TtlCheckMode         aTtlCheckMode,
510                      uint32_t             aTtl = 0) const
511     {
512         bool contains = false;
513 
514         for (const DnsRecord &record : *this)
515         {
516             if (record.Matches(aFullName.AsCString()) && (record.mType == ResourceRecord::kTypePtr) &&
517                 (record.mData.mPtrName.Matches(aPtrName.AsCString())))
518             {
519                 VerifyOrExit(record.mClass == ResourceRecord::kClassInternet);
520                 VerifyOrExit(!record.mCacheFlush); // PTR should never use cache-flush
521                 VerifyOrExit(record.MatchesTtl(aTtlCheckMode, aTtl));
522                 contains = true;
523                 ExitNow();
524             }
525         }
526 
527     exit:
528         return contains;
529     }
530 
ContainsServicesPtrot::Dns::Multicast::DnsRecords531     bool ContainsServicesPtr(const DnsNameString &aServiceType) const
532     {
533         DnsNameString allServices;
534 
535         allServices.Append("_services._dns-sd._udp.local.");
536 
537         return ContainsPtr(allServices, aServiceType, kNonZeroTtl, 0);
538     }
539 
ContainsNsecot::Dns::Multicast::DnsRecords540     bool ContainsNsec(const DnsNameString &aFullName, uint16_t aRecordType) const
541     {
542         bool contains = false;
543 
544         for (const DnsRecord &record : *this)
545         {
546             if (record.Matches(aFullName.AsCString()) && (record.mType == ResourceRecord::kTypeNsec))
547             {
548                 VerifyOrQuit(!contains); // Ensure only one NSEC record
549                 VerifyOrExit(record.mData.mNsecBitmap.ContainsType(aRecordType));
550                 contains = true;
551             }
552         }
553 
554     exit:
555         return contains;
556     }
557 };
558 
559 // Bit-flags used in `Validate()` with a `Service`
560 // to specify which records should be checked in the announce
561 // message.
562 
563 typedef uint8_t AnnounceCheckFlags;
564 
565 static constexpr uint8_t kCheckSrv         = (1 << 0);
566 static constexpr uint8_t kCheckTxt         = (1 << 1);
567 static constexpr uint8_t kCheckPtr         = (1 << 2);
568 static constexpr uint8_t kCheckServicesPtr = (1 << 3);
569 
570 enum GoodBye : bool // Used to indicate "goodbye" records (with zero TTL)
571 {
572     kNotGoodBye = false,
573     kGoodBye    = true,
574 };
575 
576 enum DnsMessageType : uint8_t
577 {
578     kMulticastQuery,
579     kMulticastResponse,
580     kUnicastResponse,
581     kLegacyUnicastResponse,
582 };
583 
584 struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMessage>
585 {
586     DnsMessage       *mNext;
587     uint32_t          mTimestamp;
588     DnsMessageType    mType;
589     Core::AddressInfo mUnicastDest;
590     Header            mHeader;
591     DnsQuestions      mQuestions;
592     DnsRecords        mAnswerRecords;
593     DnsRecords        mAuthRecords;
594     DnsRecords        mAdditionalRecords;
595 
DnsMessageot::Dns::Multicast::DnsMessage596     DnsMessage(void)
597         : mNext(nullptr)
598         , mTimestamp(sNow)
599     {
600     }
601 
RecordsForot::Dns::Multicast::DnsMessage602     const DnsRecords &RecordsFor(Section aSection) const
603     {
604         const DnsRecords *records = nullptr;
605 
606         switch (aSection)
607         {
608         case kInAnswerSection:
609             records = &mAnswerRecords;
610             break;
611         case kInAdditionalSection:
612             records = &mAdditionalRecords;
613             break;
614         }
615 
616         VerifyOrQuit(records != nullptr);
617 
618         return *records;
619     }
620 
ParseRecordsot::Dns::Multicast::DnsMessage621     void ParseRecords(const Message         &aMessage,
622                       uint16_t              &aOffset,
623                       uint16_t               aNumRecords,
624                       OwningList<DnsRecord> &aRecords,
625                       const char            *aSectionName)
626     {
627         if (aNumRecords > 0)
628         {
629             Log("   %s", aSectionName);
630         }
631 
632         for (; aNumRecords > 0; aNumRecords--)
633         {
634             DnsRecord *record = DnsRecord::Allocate();
635 
636             record->ParseFrom(aMessage, aOffset);
637             aRecords.PushAfterTail(*record);
638         }
639     }
640 
ParseFromot::Dns::Multicast::DnsMessage641     void ParseFrom(const Message &aMessage)
642     {
643         uint16_t offset = 0;
644 
645         SuccessOrQuit(aMessage.Read(offset, mHeader));
646         offset += sizeof(Header);
647 
648         Log("   %s id:%u qt:%u t:%u rcode:%u [q:%u ans:%u auth:%u addn:%u]",
649             mHeader.GetType() == Header::kTypeQuery ? "Query" : "Response", mHeader.GetMessageId(),
650             mHeader.GetQueryType(), mHeader.IsTruncationFlagSet(), mHeader.GetResponseCode(),
651             mHeader.GetQuestionCount(), mHeader.GetAnswerCount(), mHeader.GetAuthorityRecordCount(),
652             mHeader.GetAdditionalRecordCount());
653 
654         if (mHeader.GetQuestionCount() > 0)
655         {
656             Log("   Question");
657         }
658 
659         for (uint16_t num = mHeader.GetQuestionCount(); num > 0; num--)
660         {
661             DnsQuestion *question = DnsQuestion::Allocate();
662 
663             question->ParseFrom(aMessage, offset);
664             mQuestions.PushAfterTail(*question);
665         }
666 
667         ParseRecords(aMessage, offset, mHeader.GetAnswerCount(), mAnswerRecords, "Answer");
668         ParseRecords(aMessage, offset, mHeader.GetAuthorityRecordCount(), mAuthRecords, "Authority");
669         ParseRecords(aMessage, offset, mHeader.GetAdditionalRecordCount(), mAdditionalRecords, "Additional");
670     }
671 
ValidateHeaderot::Dns::Multicast::DnsMessage672     void ValidateHeader(DnsMessageType aType,
673                         uint16_t       aQuestionCount,
674                         uint16_t       aAnswerCount,
675                         uint16_t       aAuthCount,
676                         uint16_t       aAdditionalCount) const
677     {
678         VerifyOrQuit(mType == aType);
679         VerifyOrQuit(mHeader.GetQuestionCount() == aQuestionCount);
680         VerifyOrQuit(mHeader.GetAnswerCount() == aAnswerCount);
681         VerifyOrQuit(mHeader.GetAuthorityRecordCount() == aAuthCount);
682         VerifyOrQuit(mHeader.GetAdditionalRecordCount() == aAdditionalCount);
683 
684         if (aType == kUnicastResponse)
685         {
686             Ip6::Address ip6Address;
687 
688             SuccessOrQuit(ip6Address.FromString(kDeviceIp6Address));
689 
690             VerifyOrQuit(mUnicastDest.mPort == kMdnsPort);
691             VerifyOrQuit(mUnicastDest.GetAddress() == ip6Address);
692         }
693 
694         if (aType == kLegacyUnicastResponse)
695         {
696             VerifyOrQuit(mHeader.GetMessageId() == kLegacyUnicastMessageId);
697             VerifyOrQuit(mUnicastDest.mPort == kEphemeralPort);
698         }
699     }
700 
DetermineFullNameForKeyot::Dns::Multicast::DnsMessage701     static void DetermineFullNameForKey(const Core::Key &aKey, DnsNameString &aFullName)
702     {
703         if (aKey.mServiceType != nullptr)
704         {
705             aFullName.Append("%s.%s.local.", aKey.mName, aKey.mServiceType);
706         }
707         else
708         {
709             aFullName.Append("%s.local.", aKey.mName);
710         }
711     }
712 
DetermineTtlCheckModeot::Dns::Multicast::DnsMessage713     static TtlCheckMode DetermineTtlCheckMode(DnsMessageType aMessageType, bool aIsGoodBye)
714     {
715         TtlCheckMode ttlCheck;
716 
717         if (aMessageType == kLegacyUnicastResponse)
718         {
719             ttlCheck = kLegacyUnicastTtl;
720         }
721         else
722         {
723             ttlCheck = aIsGoodBye ? kZeroTtl : kNonZeroTtl;
724         }
725 
726         return ttlCheck;
727     }
728 
ValidateAsProbeForot::Dns::Multicast::DnsMessage729     void ValidateAsProbeFor(const Core::Host &aHost, bool aUnicastResponse) const
730     {
731         DnsNameString fullName;
732 
733         VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
734         VerifyOrQuit(!mHeader.IsTruncationFlagSet());
735 
736         fullName.Append("%s.local.", aHost.mHostName);
737         VerifyOrQuit(mQuestions.Contains(fullName, aUnicastResponse));
738 
739         for (uint16_t index = 0; index < aHost.mAddressesLength; index++)
740         {
741             VerifyOrQuit(mAuthRecords.ContainsAaaa(fullName, AsCoreType(&aHost.mAddresses[index]), !kCacheFlush,
742                                                    kNonZeroTtl, aHost.mTtl));
743         }
744     }
745 
ValidateAsProbeForot::Dns::Multicast::DnsMessage746     void ValidateAsProbeFor(const Core::Service &aService, bool aUnicastResponse) const
747     {
748         DnsNameString serviceName;
749 
750         VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
751         VerifyOrQuit(!mHeader.IsTruncationFlagSet());
752 
753         serviceName.Append("%s.%s.local.", aService.mServiceInstance, aService.mServiceType);
754 
755         VerifyOrQuit(mQuestions.Contains(serviceName, aUnicastResponse));
756 
757         VerifyOrQuit(mAuthRecords.ContainsSrv(serviceName, aService, !kCacheFlush, kNonZeroTtl, aService.mTtl));
758         VerifyOrQuit(mAuthRecords.ContainsTxt(serviceName, aService, !kCacheFlush, kNonZeroTtl, aService.mTtl));
759     }
760 
ValidateAsProbeForot::Dns::Multicast::DnsMessage761     void ValidateAsProbeFor(const Core::Key &aKey, bool aUnicastResponse) const
762     {
763         DnsNameString fullName;
764 
765         VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
766         VerifyOrQuit(!mHeader.IsTruncationFlagSet());
767 
768         DetermineFullNameForKey(aKey, fullName);
769 
770         VerifyOrQuit(mQuestions.Contains(fullName, aUnicastResponse));
771         VerifyOrQuit(mAuthRecords.ContainsKey(fullName, Data(aKey.mKeyData, aKey.mKeyDataLength), !kCacheFlush,
772                                               kNonZeroTtl, aKey.mTtl));
773     }
774 
Validateot::Dns::Multicast::DnsMessage775     void Validate(const Core::Host &aHost, Section aSection, GoodBye aIsGoodBye = kNotGoodBye) const
776     {
777         DnsNameString fullName;
778         TtlCheckMode  ttlCheck;
779 
780         bool cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
781 
782         ttlCheck = DetermineTtlCheckMode(mType, aIsGoodBye);
783 
784         VerifyOrQuit(mHeader.GetType() == Header::kTypeResponse);
785 
786         fullName.Append("%s.local.", aHost.mHostName);
787 
788         for (uint16_t index = 0; index < aHost.mAddressesLength; index++)
789         {
790             VerifyOrQuit(RecordsFor(aSection).ContainsAaaa(fullName, AsCoreType(&aHost.mAddresses[index]),
791                                                            cacheFlushSet, ttlCheck, aHost.mTtl));
792         }
793 
794         if (!aIsGoodBye && (aSection == kInAnswerSection))
795         {
796             VerifyOrQuit(mAdditionalRecords.ContainsNsec(fullName, ResourceRecord::kTypeAaaa));
797         }
798     }
799 
Validateot::Dns::Multicast::DnsMessage800     void Validate(const Core::Service &aService,
801                   Section              aSection,
802                   AnnounceCheckFlags   aCheckFlags,
803                   GoodBye              aIsGoodBye = kNotGoodBye) const
804     {
805         DnsNameString serviceName;
806         DnsNameString serviceType;
807         TtlCheckMode  ttlCheck;
808         bool          checkNsec     = false;
809         bool          cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
810 
811         ttlCheck = DetermineTtlCheckMode(mType, aIsGoodBye);
812 
813         VerifyOrQuit(mHeader.GetType() == Header::kTypeResponse);
814 
815         serviceName.Append("%s.%s.local.", aService.mServiceInstance, aService.mServiceType);
816         serviceType.Append("%s.local.", aService.mServiceType);
817 
818         if (aCheckFlags & kCheckSrv)
819         {
820             VerifyOrQuit(
821                 RecordsFor(aSection).ContainsSrv(serviceName, aService, cacheFlushSet, ttlCheck, aService.mTtl));
822 
823             checkNsec = true;
824         }
825 
826         if (aCheckFlags & kCheckTxt)
827         {
828             VerifyOrQuit(
829                 RecordsFor(aSection).ContainsTxt(serviceName, aService, cacheFlushSet, ttlCheck, aService.mTtl));
830 
831             checkNsec = true;
832         }
833 
834         if (aCheckFlags & kCheckPtr)
835         {
836             VerifyOrQuit(RecordsFor(aSection).ContainsPtr(serviceType, serviceName, ttlCheck, aService.mTtl));
837         }
838 
839         if (aCheckFlags & kCheckServicesPtr)
840         {
841             VerifyOrQuit(RecordsFor(aSection).ContainsServicesPtr(serviceType));
842         }
843 
844         if (!aIsGoodBye && checkNsec && (aSection == kInAnswerSection))
845         {
846             VerifyOrQuit(mAdditionalRecords.ContainsNsec(serviceName, ResourceRecord::kTypeSrv));
847             VerifyOrQuit(mAdditionalRecords.ContainsNsec(serviceName, ResourceRecord::kTypeTxt));
848         }
849     }
850 
Validateot::Dns::Multicast::DnsMessage851     void Validate(const Core::Key &aKey, Section aSection, GoodBye aIsGoodBye = kNotGoodBye) const
852     {
853         DnsNameString fullName;
854         TtlCheckMode  ttlCheck;
855         bool          cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
856 
857         VerifyOrQuit(mHeader.GetType() == Header::kTypeResponse);
858 
859         DetermineFullNameForKey(aKey, fullName);
860 
861         ttlCheck = DetermineTtlCheckMode(mType, aIsGoodBye);
862 
863         VerifyOrQuit(RecordsFor(aSection).ContainsKey(fullName, Data(aKey.mKeyData, aKey.mKeyDataLength), cacheFlushSet,
864                                                       ttlCheck, aKey.mTtl));
865 
866         if (!aIsGoodBye && (aSection == kInAnswerSection))
867         {
868             VerifyOrQuit(mAdditionalRecords.ContainsNsec(fullName, ResourceRecord::kTypeKey));
869         }
870     }
871 
ValidateSubTypeot::Dns::Multicast::DnsMessage872     void ValidateSubType(const char *aSubLabel, const Core::Service &aService, GoodBye aIsGoodBye = kNotGoodBye) const
873     {
874         DnsNameString serviceName;
875         DnsNameString subServiceType;
876 
877         VerifyOrQuit(mHeader.GetType() == Header::kTypeResponse);
878 
879         serviceName.Append("%s.%s.local.", aService.mServiceInstance, aService.mServiceType);
880         subServiceType.Append("%s._sub.%s.local.", aSubLabel, aService.mServiceType);
881 
882         VerifyOrQuit(mAnswerRecords.ContainsPtr(subServiceType, serviceName, aIsGoodBye ? kZeroTtl : kNonZeroTtl,
883                                                 aService.mTtl));
884     }
885 
ValidateAsQueryForot::Dns::Multicast::DnsMessage886     void ValidateAsQueryFor(const Core::Browser &aBrowser) const
887     {
888         DnsNameString fullServiceType;
889 
890         VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
891         VerifyOrQuit(!mHeader.IsTruncationFlagSet());
892 
893         if (aBrowser.mSubTypeLabel == nullptr)
894         {
895             fullServiceType.Append("%s.local.", aBrowser.mServiceType);
896         }
897         else
898         {
899             fullServiceType.Append("%s._sub.%s.local", aBrowser.mSubTypeLabel, aBrowser.mServiceType);
900         }
901 
902         VerifyOrQuit(mQuestions.Contains(ResourceRecord::kTypePtr, fullServiceType));
903     }
904 
ValidateAsQueryForot::Dns::Multicast::DnsMessage905     void ValidateAsQueryFor(const Core::SrvResolver &aResolver) const
906     {
907         DnsNameString fullName;
908 
909         VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
910         VerifyOrQuit(!mHeader.IsTruncationFlagSet());
911 
912         fullName.Append("%s.%s.local.", aResolver.mServiceInstance, aResolver.mServiceType);
913 
914         VerifyOrQuit(mQuestions.Contains(ResourceRecord::kTypeSrv, fullName));
915     }
916 
ValidateAsQueryForot::Dns::Multicast::DnsMessage917     void ValidateAsQueryFor(const Core::TxtResolver &aResolver) const
918     {
919         DnsNameString fullName;
920 
921         VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
922         VerifyOrQuit(!mHeader.IsTruncationFlagSet());
923 
924         fullName.Append("%s.%s.local.", aResolver.mServiceInstance, aResolver.mServiceType);
925 
926         VerifyOrQuit(mQuestions.Contains(ResourceRecord::kTypeTxt, fullName));
927     }
928 
ValidateAsQueryForot::Dns::Multicast::DnsMessage929     void ValidateAsQueryFor(const Core::AddressResolver &aResolver) const
930     {
931         DnsNameString fullName;
932 
933         VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
934         VerifyOrQuit(!mHeader.IsTruncationFlagSet());
935 
936         fullName.Append("%s.local.", aResolver.mHostName);
937 
938         VerifyOrQuit(mQuestions.Contains(ResourceRecord::kTypeAaaa, fullName));
939     }
940 };
941 
942 struct RegCallback
943 {
Resetot::Dns::Multicast::RegCallback944     void Reset(void) { mWasCalled = false; }
945 
946     bool  mWasCalled;
947     Error mError;
948 };
949 
950 static constexpr uint16_t kMaxCallbacks = 8;
951 
952 static RegCallback sRegCallbacks[kMaxCallbacks];
953 
HandleCallback(otInstance * aInstance,otMdnsRequestId aRequestId,otError aError)954 static void HandleCallback(otInstance *aInstance, otMdnsRequestId aRequestId, otError aError)
955 {
956     Log("Register callback - ResuestId:%u Error:%s", aRequestId, otThreadErrorToString(aError));
957 
958     VerifyOrQuit(aInstance == sInstance);
959     VerifyOrQuit(aRequestId < kMaxCallbacks);
960 
961     VerifyOrQuit(!sRegCallbacks[aRequestId].mWasCalled);
962 
963     sRegCallbacks[aRequestId].mWasCalled = true;
964     sRegCallbacks[aRequestId].mError     = aError;
965 }
966 
HandleSuccessCallback(otInstance * aInstance,otMdnsRequestId aRequestId,otError aError)967 static void HandleSuccessCallback(otInstance *aInstance, otMdnsRequestId aRequestId, otError aError)
968 {
969     HandleCallback(aInstance, aRequestId, aError);
970     SuccessOrQuit(aError);
971 }
972 
973 struct ConflictCallback
974 {
Resetot::Dns::Multicast::ConflictCallback975     void Reset(void) { mWasCalled = false; }
976 
Handleot::Dns::Multicast::ConflictCallback977     void Handle(const char *aName, const char *aServiceType)
978     {
979         VerifyOrQuit(!mWasCalled);
980 
981         mWasCalled = true;
982         mName.Clear();
983         mName.Append("%s", aName);
984 
985         mHasServiceType = (aServiceType != nullptr);
986         VerifyOrExit(mHasServiceType);
987         mServiceType.Clear();
988         mServiceType.Append("%s", aServiceType);
989 
990     exit:
991         return;
992     }
993 
994     bool          mWasCalled;
995     bool          mHasServiceType;
996     DnsNameString mName;
997     DnsNameString mServiceType;
998 };
999 
1000 static ConflictCallback sConflictCallback;
1001 
HandleConflict(otInstance * aInstance,const char * aName,const char * aServiceType)1002 static void HandleConflict(otInstance *aInstance, const char *aName, const char *aServiceType)
1003 {
1004     Log("Conflict callback - %s %s", aName, (aServiceType == nullptr) ? "" : aServiceType);
1005 
1006     VerifyOrQuit(aInstance == sInstance);
1007     sConflictCallback.Handle(aName, aServiceType);
1008 }
1009 
1010 //---------------------------------------------------------------------------------------------------------------------
1011 // Helper functions and methods
1012 
RecordTypeToString(uint16_t aType)1013 static const char *RecordTypeToString(uint16_t aType)
1014 {
1015     const char *str = "Other";
1016 
1017     switch (aType)
1018     {
1019     case ResourceRecord::kTypeZero:
1020         str = "ZERO";
1021         break;
1022     case ResourceRecord::kTypeA:
1023         str = "A";
1024         break;
1025     case ResourceRecord::kTypeSoa:
1026         str = "SOA";
1027         break;
1028     case ResourceRecord::kTypeCname:
1029         str = "CNAME";
1030         break;
1031     case ResourceRecord::kTypePtr:
1032         str = "PTR";
1033         break;
1034     case ResourceRecord::kTypeTxt:
1035         str = "TXT";
1036         break;
1037     case ResourceRecord::kTypeSig:
1038         str = "SIG";
1039         break;
1040     case ResourceRecord::kTypeKey:
1041         str = "KEY";
1042         break;
1043     case ResourceRecord::kTypeAaaa:
1044         str = "AAAA";
1045         break;
1046     case ResourceRecord::kTypeSrv:
1047         str = "SRV";
1048         break;
1049     case ResourceRecord::kTypeOpt:
1050         str = "OPT";
1051         break;
1052     case ResourceRecord::kTypeNsec:
1053         str = "NSEC";
1054         break;
1055     case ResourceRecord::kTypeAny:
1056         str = "ANY";
1057         break;
1058     }
1059 
1060     return str;
1061 }
1062 
ParseMessage(const Message & aMessage,const Core::AddressInfo * aUnicastDest)1063 static void ParseMessage(const Message &aMessage, const Core::AddressInfo *aUnicastDest)
1064 {
1065     DnsMessage *msg = DnsMessage::Allocate();
1066 
1067     msg->ParseFrom(aMessage);
1068 
1069     switch (msg->mHeader.GetType())
1070     {
1071     case Header::kTypeQuery:
1072         msg->mType = kMulticastQuery;
1073         VerifyOrQuit(aUnicastDest == nullptr);
1074         break;
1075 
1076     case Header::kTypeResponse:
1077         if (aUnicastDest == nullptr)
1078         {
1079             msg->mType = kMulticastResponse;
1080         }
1081         else
1082         {
1083             msg->mType        = (aUnicastDest->mPort == kEphemeralPort) ? kLegacyUnicastResponse : kUnicastResponse;
1084             msg->mUnicastDest = *aUnicastDest;
1085         }
1086     }
1087 
1088     sDnsMessages.PushAfterTail(*msg);
1089 }
1090 
SendQuery(const char * aName,uint16_t aRecordType,uint16_t aRecordClass=ResourceRecord::kClassInternet,bool aTruncated=false,bool aLegacyUnicastQuery=false)1091 static void SendQuery(const char *aName,
1092                       uint16_t    aRecordType,
1093                       uint16_t    aRecordClass        = ResourceRecord::kClassInternet,
1094                       bool        aTruncated          = false,
1095                       bool        aLegacyUnicastQuery = false)
1096 {
1097     Message          *message;
1098     Header            header;
1099     Core::AddressInfo senderAddrInfo;
1100 
1101     message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
1102     VerifyOrQuit(message != nullptr);
1103 
1104     header.Clear();
1105     header.SetType(Header::kTypeQuery);
1106     header.SetQuestionCount(1);
1107 
1108     if (aLegacyUnicastQuery)
1109     {
1110         header.SetMessageId(kLegacyUnicastMessageId);
1111     }
1112 
1113     if (aTruncated)
1114     {
1115         header.SetTruncationFlag();
1116     }
1117 
1118     SuccessOrQuit(message->Append(header));
1119     SuccessOrQuit(Name::AppendName(aName, *message));
1120     SuccessOrQuit(message->Append(Question(aRecordType, aRecordClass)));
1121 
1122     SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
1123     senderAddrInfo.mPort         = aLegacyUnicastQuery ? kEphemeralPort : kMdnsPort;
1124     senderAddrInfo.mInfraIfIndex = 0;
1125 
1126     Log("Sending query for %s %s", aName, RecordTypeToString(aRecordType));
1127 
1128     otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
1129 }
1130 
SendQueryForTwo(const char * aName1,uint16_t aRecordType1,const char * aName2,uint16_t aRecordType2,bool aIsLegacyUnicast=false)1131 static void SendQueryForTwo(const char *aName1,
1132                             uint16_t    aRecordType1,
1133                             const char *aName2,
1134                             uint16_t    aRecordType2,
1135                             bool        aIsLegacyUnicast = false)
1136 {
1137     // Send query with two questions.
1138 
1139     Message          *message;
1140     Header            header;
1141     Core::AddressInfo senderAddrInfo;
1142 
1143     message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
1144     VerifyOrQuit(message != nullptr);
1145 
1146     header.Clear();
1147     header.SetType(Header::kTypeQuery);
1148     header.SetQuestionCount(2);
1149 
1150     SuccessOrQuit(message->Append(header));
1151     SuccessOrQuit(Name::AppendName(aName1, *message));
1152     SuccessOrQuit(message->Append(Question(aRecordType1, ResourceRecord::kClassInternet)));
1153     SuccessOrQuit(Name::AppendName(aName2, *message));
1154     SuccessOrQuit(message->Append(Question(aRecordType2, ResourceRecord::kClassInternet)));
1155 
1156     SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
1157     senderAddrInfo.mPort         = aIsLegacyUnicast ? kEphemeralPort : kMdnsPort;
1158     senderAddrInfo.mInfraIfIndex = 0;
1159 
1160     Log("Sending query for %s %s and %s %s", aName1, RecordTypeToString(aRecordType1), aName2,
1161         RecordTypeToString(aRecordType2));
1162 
1163     otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
1164 }
1165 
SendPtrResponse(const char * aName,const char * aPtrName,uint32_t aTtl,Section aSection)1166 static void SendPtrResponse(const char *aName, const char *aPtrName, uint32_t aTtl, Section aSection)
1167 {
1168     Message          *message;
1169     Header            header;
1170     PtrRecord         ptr;
1171     Core::AddressInfo senderAddrInfo;
1172 
1173     message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
1174     VerifyOrQuit(message != nullptr);
1175 
1176     header.Clear();
1177     header.SetType(Header::kTypeResponse);
1178 
1179     switch (aSection)
1180     {
1181     case kInAnswerSection:
1182         header.SetAnswerCount(1);
1183         break;
1184     case kInAdditionalSection:
1185         header.SetAdditionalRecordCount(1);
1186         break;
1187     }
1188 
1189     SuccessOrQuit(message->Append(header));
1190     SuccessOrQuit(Name::AppendName(aName, *message));
1191 
1192     ptr.Init();
1193     ptr.SetTtl(aTtl);
1194     ptr.SetLength(StringLength(aPtrName, Name::kMaxNameSize) + 1);
1195     SuccessOrQuit(message->Append(ptr));
1196     SuccessOrQuit(Name::AppendName(aPtrName, *message));
1197 
1198     SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
1199     senderAddrInfo.mPort         = kMdnsPort;
1200     senderAddrInfo.mInfraIfIndex = 0;
1201 
1202     Log("Sending PTR response for %s with %s, ttl:%lu", aName, aPtrName, ToUlong(aTtl));
1203 
1204     otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
1205 }
1206 
SendSrvResponse(const char * aServiceName,const char * aHostName,uint16_t aPort,uint16_t aPriority,uint16_t aWeight,uint32_t aTtl,Section aSection)1207 static void SendSrvResponse(const char *aServiceName,
1208                             const char *aHostName,
1209                             uint16_t    aPort,
1210                             uint16_t    aPriority,
1211                             uint16_t    aWeight,
1212                             uint32_t    aTtl,
1213                             Section     aSection)
1214 {
1215     Message          *message;
1216     Header            header;
1217     SrvRecord         srv;
1218     Core::AddressInfo senderAddrInfo;
1219 
1220     message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
1221     VerifyOrQuit(message != nullptr);
1222 
1223     header.Clear();
1224     header.SetType(Header::kTypeResponse);
1225 
1226     switch (aSection)
1227     {
1228     case kInAnswerSection:
1229         header.SetAnswerCount(1);
1230         break;
1231     case kInAdditionalSection:
1232         header.SetAdditionalRecordCount(1);
1233         break;
1234     }
1235 
1236     SuccessOrQuit(message->Append(header));
1237     SuccessOrQuit(Name::AppendName(aServiceName, *message));
1238 
1239     srv.Init();
1240     srv.SetTtl(aTtl);
1241     srv.SetPort(aPort);
1242     srv.SetPriority(aPriority);
1243     srv.SetWeight(aWeight);
1244     srv.SetLength(sizeof(srv) - sizeof(ResourceRecord) + StringLength(aHostName, Name::kMaxNameSize) + 1);
1245     SuccessOrQuit(message->Append(srv));
1246     SuccessOrQuit(Name::AppendName(aHostName, *message));
1247 
1248     SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
1249     senderAddrInfo.mPort         = kMdnsPort;
1250     senderAddrInfo.mInfraIfIndex = 0;
1251 
1252     Log("Sending SRV response for %s, host:%s, port:%u, ttl:%lu", aServiceName, aHostName, aPort, ToUlong(aTtl));
1253 
1254     otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
1255 }
1256 
SendTxtResponse(const char * aServiceName,const uint8_t * aTxtData,uint16_t aTxtDataLength,uint32_t aTtl,Section aSection)1257 static void SendTxtResponse(const char    *aServiceName,
1258                             const uint8_t *aTxtData,
1259                             uint16_t       aTxtDataLength,
1260                             uint32_t       aTtl,
1261                             Section        aSection)
1262 {
1263     Message          *message;
1264     Header            header;
1265     TxtRecord         txt;
1266     Core::AddressInfo senderAddrInfo;
1267 
1268     message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
1269     VerifyOrQuit(message != nullptr);
1270 
1271     header.Clear();
1272     header.SetType(Header::kTypeResponse);
1273 
1274     switch (aSection)
1275     {
1276     case kInAnswerSection:
1277         header.SetAnswerCount(1);
1278         break;
1279     case kInAdditionalSection:
1280         header.SetAdditionalRecordCount(1);
1281         break;
1282     }
1283 
1284     SuccessOrQuit(message->Append(header));
1285     SuccessOrQuit(Name::AppendName(aServiceName, *message));
1286 
1287     txt.Init();
1288     txt.SetTtl(aTtl);
1289     txt.SetLength(aTxtDataLength);
1290     SuccessOrQuit(message->Append(txt));
1291     SuccessOrQuit(message->AppendBytes(aTxtData, aTxtDataLength));
1292 
1293     SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
1294     senderAddrInfo.mPort         = kMdnsPort;
1295     senderAddrInfo.mInfraIfIndex = 0;
1296 
1297     Log("Sending TXT response for %s, len:%u, ttl:%lu", aServiceName, aTxtDataLength, ToUlong(aTtl));
1298 
1299     otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
1300 }
1301 
SendHostAddrResponse(const char * aHostName,AddrAndTtl * aAddrAndTtls,uint32_t aNumAddrs,bool aCacheFlush,Section aSection)1302 static void SendHostAddrResponse(const char *aHostName,
1303                                  AddrAndTtl *aAddrAndTtls,
1304                                  uint32_t    aNumAddrs,
1305                                  bool        aCacheFlush,
1306                                  Section     aSection)
1307 {
1308     Message          *message;
1309     Header            header;
1310     AaaaRecord        record;
1311     Core::AddressInfo senderAddrInfo;
1312 
1313     message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
1314     VerifyOrQuit(message != nullptr);
1315 
1316     header.Clear();
1317     header.SetType(Header::kTypeResponse);
1318 
1319     switch (aSection)
1320     {
1321     case kInAnswerSection:
1322         header.SetAnswerCount(aNumAddrs);
1323         break;
1324     case kInAdditionalSection:
1325         header.SetAdditionalRecordCount(aNumAddrs);
1326         break;
1327     }
1328 
1329     SuccessOrQuit(message->Append(header));
1330 
1331     record.Init();
1332 
1333     if (aCacheFlush)
1334     {
1335         record.SetClass(record.GetClass() | kClassCacheFlushFlag);
1336     }
1337 
1338     Log("Sending AAAA response for %s numAddrs:%u, cach-flush:%u", aHostName, aNumAddrs, aCacheFlush);
1339 
1340     for (uint32_t index = 0; index < aNumAddrs; index++)
1341     {
1342         record.SetTtl(aAddrAndTtls[index].mTtl);
1343         record.SetAddress(aAddrAndTtls[index].mAddress);
1344 
1345         SuccessOrQuit(Name::AppendName(aHostName, *message));
1346         SuccessOrQuit(message->Append(record));
1347 
1348         Log(" - %s, ttl:%lu", aAddrAndTtls[index].mAddress.ToString().AsCString(), ToUlong(aAddrAndTtls[index].mTtl));
1349     }
1350 
1351     SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
1352     senderAddrInfo.mPort         = kMdnsPort;
1353     senderAddrInfo.mInfraIfIndex = 0;
1354 
1355     otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
1356 }
1357 
SendResponseWithEmptyKey(const char * aName,Section aSection)1358 static void SendResponseWithEmptyKey(const char *aName, Section aSection)
1359 {
1360     Message          *message;
1361     Header            header;
1362     ResourceRecord    record;
1363     Core::AddressInfo senderAddrInfo;
1364 
1365     message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
1366     VerifyOrQuit(message != nullptr);
1367 
1368     header.Clear();
1369     header.SetType(Header::kTypeResponse);
1370 
1371     switch (aSection)
1372     {
1373     case kInAnswerSection:
1374         header.SetAnswerCount(1);
1375         break;
1376     case kInAdditionalSection:
1377         header.SetAdditionalRecordCount(1);
1378         break;
1379     }
1380 
1381     SuccessOrQuit(message->Append(header));
1382     SuccessOrQuit(Name::AppendName(aName, *message));
1383 
1384     record.Init(ResourceRecord::kTypeKey);
1385     record.SetTtl(4500);
1386     record.SetLength(0);
1387     SuccessOrQuit(message->Append(record));
1388 
1389     SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
1390     senderAddrInfo.mPort         = kMdnsPort;
1391     senderAddrInfo.mInfraIfIndex = 0;
1392 
1393     Log("Sending response with empty key for %s", aName);
1394 
1395     otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
1396 }
1397 
1398 struct KnownAnswer
1399 {
1400     const char *mPtrAnswer;
1401     uint32_t    mTtl;
1402 };
1403 
SendPtrQueryWithKnownAnswers(const char * aName,const KnownAnswer * aKnownAnswers,uint16_t aNumAnswers)1404 static void SendPtrQueryWithKnownAnswers(const char *aName, const KnownAnswer *aKnownAnswers, uint16_t aNumAnswers)
1405 {
1406     Message          *message;
1407     Header            header;
1408     Core::AddressInfo senderAddrInfo;
1409     uint16_t          nameOffset;
1410 
1411     message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
1412     VerifyOrQuit(message != nullptr);
1413 
1414     header.Clear();
1415     header.SetType(Header::kTypeQuery);
1416     header.SetQuestionCount(1);
1417     header.SetAnswerCount(aNumAnswers);
1418 
1419     SuccessOrQuit(message->Append(header));
1420     nameOffset = message->GetLength();
1421     SuccessOrQuit(Name::AppendName(aName, *message));
1422     SuccessOrQuit(message->Append(Question(ResourceRecord::kTypePtr, ResourceRecord::kClassInternet)));
1423 
1424     for (uint16_t index = 0; index < aNumAnswers; index++)
1425     {
1426         PtrRecord ptr;
1427 
1428         ptr.Init();
1429         ptr.SetTtl(aKnownAnswers[index].mTtl);
1430         ptr.SetLength(StringLength(aKnownAnswers[index].mPtrAnswer, Name::kMaxNameSize) + 1);
1431 
1432         SuccessOrQuit(Name::AppendPointerLabel(nameOffset, *message));
1433         SuccessOrQuit(message->Append(ptr));
1434         SuccessOrQuit(Name::AppendName(aKnownAnswers[index].mPtrAnswer, *message));
1435     }
1436 
1437     SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
1438     senderAddrInfo.mPort         = kMdnsPort;
1439     senderAddrInfo.mInfraIfIndex = 0;
1440 
1441     Log("Sending query for %s PTR with %u known-answers", aName, aNumAnswers);
1442 
1443     otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
1444 }
1445 
SendEmtryPtrQueryWithKnownAnswers(const char * aName,const KnownAnswer * aKnownAnswers,uint16_t aNumAnswers)1446 static void SendEmtryPtrQueryWithKnownAnswers(const char *aName, const KnownAnswer *aKnownAnswers, uint16_t aNumAnswers)
1447 {
1448     Message          *message;
1449     Header            header;
1450     Core::AddressInfo senderAddrInfo;
1451     uint16_t          nameOffset = 0;
1452 
1453     message = sInstance->Get<MessagePool>().Allocate(Message::kTypeOther);
1454     VerifyOrQuit(message != nullptr);
1455 
1456     header.Clear();
1457     header.SetType(Header::kTypeQuery);
1458     header.SetAnswerCount(aNumAnswers);
1459 
1460     SuccessOrQuit(message->Append(header));
1461 
1462     for (uint16_t index = 0; index < aNumAnswers; index++)
1463     {
1464         PtrRecord ptr;
1465 
1466         ptr.Init();
1467         ptr.SetTtl(aKnownAnswers[index].mTtl);
1468         ptr.SetLength(StringLength(aKnownAnswers[index].mPtrAnswer, Name::kMaxNameSize) + 1);
1469 
1470         if (nameOffset == 0)
1471         {
1472             nameOffset = message->GetLength();
1473             SuccessOrQuit(Name::AppendName(aName, *message));
1474         }
1475         else
1476         {
1477             SuccessOrQuit(Name::AppendPointerLabel(nameOffset, *message));
1478         }
1479 
1480         SuccessOrQuit(message->Append(ptr));
1481         SuccessOrQuit(Name::AppendName(aKnownAnswers[index].mPtrAnswer, *message));
1482     }
1483 
1484     SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
1485     senderAddrInfo.mPort         = kMdnsPort;
1486     senderAddrInfo.mInfraIfIndex = 0;
1487 
1488     Log("Sending empty query with %u known-answers for %s", aNumAnswers, aName);
1489 
1490     otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
1491 }
1492 
1493 //----------------------------------------------------------------------------------------------------------------------
1494 // `otPlatLog`
1495 
1496 extern "C" {
1497 
1498 #if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED
otPlatLog(otLogLevel aLogLevel,otLogRegion aLogRegion,const char * aFormat,...)1499 void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
1500 {
1501     OT_UNUSED_VARIABLE(aLogLevel);
1502     OT_UNUSED_VARIABLE(aLogRegion);
1503     OT_UNUSED_VARIABLE(aFormat);
1504 
1505 #if ENABLE_TEST_LOG
1506     va_list args;
1507 
1508     printf("   ");
1509     va_start(args, aFormat);
1510     vprintf(aFormat, args);
1511     va_end(args);
1512 
1513     printf("\n");
1514 #endif
1515 }
1516 
1517 #endif
1518 
1519 //----------------------------------------------------------------------------------------------------------------------
1520 // `otPlatAlarm`
1521 
otPlatAlarmMilliStop(otInstance *)1522 void otPlatAlarmMilliStop(otInstance *) { sAlarmOn = false; }
1523 
otPlatAlarmMilliStartAt(otInstance *,uint32_t aT0,uint32_t aDt)1524 void otPlatAlarmMilliStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
1525 {
1526     sAlarmOn   = true;
1527     sAlarmTime = aT0 + aDt;
1528 }
1529 
otPlatAlarmMilliGetNow(void)1530 uint32_t otPlatAlarmMilliGetNow(void) { return sNow; }
1531 
1532 //----------------------------------------------------------------------------------------------------------------------
1533 // Heap allocation
1534 
1535 Array<void *, 500> sHeapAllocatedPtrs;
1536 
1537 #if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
1538 
otPlatCAlloc(size_t aNum,size_t aSize)1539 void *otPlatCAlloc(size_t aNum, size_t aSize)
1540 {
1541     void *ptr = calloc(aNum, aSize);
1542 
1543     SuccessOrQuit(sHeapAllocatedPtrs.PushBack(ptr));
1544 
1545     return ptr;
1546 }
1547 
otPlatFree(void * aPtr)1548 void otPlatFree(void *aPtr)
1549 {
1550     if (aPtr != nullptr)
1551     {
1552         void **entry = sHeapAllocatedPtrs.Find(aPtr);
1553 
1554         VerifyOrQuit(entry != nullptr, "A heap allocated item is freed twice");
1555         sHeapAllocatedPtrs.Remove(*entry);
1556     }
1557 
1558     free(aPtr);
1559 }
1560 
1561 #endif
1562 
1563 //----------------------------------------------------------------------------------------------------------------------
1564 // `otPlatMdns`
1565 
otPlatMdnsSetListeningEnabled(otInstance * aInstance,bool aEnable,uint32_t aInfraIfIndex)1566 otError otPlatMdnsSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
1567 {
1568     VerifyOrQuit(aInstance == sInstance);
1569     sInfraIfIndex = aInfraIfIndex;
1570 
1571     Log("otPlatMdnsSetListeningEnabled(%s)", aEnable ? "true" : "false");
1572 
1573     return kErrorNone;
1574 }
1575 
otPlatMdnsSendMulticast(otInstance * aInstance,otMessage * aMessage,uint32_t aInfraIfIndex)1576 void otPlatMdnsSendMulticast(otInstance *aInstance, otMessage *aMessage, uint32_t aInfraIfIndex)
1577 {
1578     Message          &message = AsCoreType(aMessage);
1579     Core::AddressInfo senderAddrInfo;
1580 
1581     VerifyOrQuit(aInfraIfIndex == sInfraIfIndex);
1582 
1583     Log("otPlatMdnsSendMulticast(msg-len:%u)", message.GetLength());
1584     ParseMessage(message, nullptr);
1585 
1586     // Pass the multicast message back.
1587 
1588     SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
1589     senderAddrInfo.mPort         = kMdnsPort;
1590     senderAddrInfo.mInfraIfIndex = 0;
1591 
1592     otPlatMdnsHandleReceive(sInstance, aMessage, /* aIsUnicast */ false, &senderAddrInfo);
1593 }
1594 
otPlatMdnsSendUnicast(otInstance * aInstance,otMessage * aMessage,const otPlatMdnsAddressInfo * aAddress)1595 void otPlatMdnsSendUnicast(otInstance *aInstance, otMessage *aMessage, const otPlatMdnsAddressInfo *aAddress)
1596 {
1597     Message                 &message = AsCoreType(aMessage);
1598     const Core::AddressInfo &address = AsCoreType(aAddress);
1599     Ip6::Address             deviceAddress;
1600 
1601     Log("otPlatMdnsSendUnicast() - [%s]:%u", address.GetAddress().ToString().AsCString(), address.mPort);
1602     ParseMessage(message, AsCoreTypePtr(aAddress));
1603 
1604     SuccessOrQuit(deviceAddress.FromString(kDeviceIp6Address));
1605 
1606     if ((address.GetAddress() == deviceAddress) && (address.mPort == kMdnsPort))
1607     {
1608         Core::AddressInfo senderAddrInfo;
1609 
1610         SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
1611         senderAddrInfo.mPort         = kMdnsPort;
1612         senderAddrInfo.mInfraIfIndex = 0;
1613 
1614         Log("otPlatMdnsSendUnicast() - unicast msg matches this device address, passing it back");
1615         otPlatMdnsHandleReceive(sInstance, &message, /* aIsUnicast */ true, &senderAddrInfo);
1616     }
1617     else
1618     {
1619         message.Free();
1620     }
1621 }
1622 
1623 } // extern "C"
1624 
1625 //---------------------------------------------------------------------------------------------------------------------
1626 
ProcessTasklets(void)1627 void ProcessTasklets(void)
1628 {
1629     while (otTaskletsArePending(sInstance))
1630     {
1631         otTaskletsProcess(sInstance);
1632     }
1633 }
1634 
AdvanceTime(uint32_t aDuration)1635 void AdvanceTime(uint32_t aDuration)
1636 {
1637     uint32_t time = sNow + aDuration;
1638 
1639     Log("AdvanceTime for %u.%03u", aDuration / 1000, aDuration % 1000);
1640 
1641     while (TimeMilli(sAlarmTime) <= TimeMilli(time))
1642     {
1643         ProcessTasklets();
1644         sNow = sAlarmTime;
1645         otPlatAlarmMilliFired(sInstance);
1646     }
1647 
1648     ProcessTasklets();
1649     sNow = time;
1650 }
1651 
InitTest(void)1652 Core *InitTest(void)
1653 {
1654     sNow     = 0;
1655     sAlarmOn = false;
1656 
1657     sDnsMessages.Clear();
1658 
1659     for (RegCallback &regCallbck : sRegCallbacks)
1660     {
1661         regCallbck.Reset();
1662     }
1663 
1664     sConflictCallback.Reset();
1665 
1666     sInstance = testInitInstance();
1667 
1668     VerifyOrQuit(sInstance != nullptr);
1669 
1670     return &sInstance->Get<Core>();
1671 }
1672 
1673 //----------------------------------------------------------------------------------------------------------------------
1674 
1675 static const uint8_t kKey1[]         = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
1676 static const uint8_t kKey2[]         = {0x12, 0x34, 0x56};
1677 static const uint8_t kTxtData1[]     = {3, 'a', '=', '1', 0};
1678 static const uint8_t kTxtData2[]     = {1, 'b', 0};
1679 static const uint8_t kEmptyTxtData[] = {0};
1680 
1681 //---------------------------------------------------------------------------------------------------------------------
1682 
TestHostReg(void)1683 void TestHostReg(void)
1684 {
1685     Core             *mdns = InitTest();
1686     Core::Host        host;
1687     Ip6::Address      hostAddresses[3];
1688     const DnsMessage *dnsMsg;
1689     uint16_t          heapAllocations;
1690     DnsNameString     hostFullName;
1691 
1692     Log("-------------------------------------------------------------------------------------------");
1693     Log("TestHostReg");
1694 
1695     AdvanceTime(1);
1696 
1697     heapAllocations = sHeapAllocatedPtrs.GetLength();
1698     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
1699 
1700     SuccessOrQuit(hostAddresses[0].FromString("fd00::aaaa"));
1701     SuccessOrQuit(hostAddresses[1].FromString("fd00::bbbb"));
1702     SuccessOrQuit(hostAddresses[2].FromString("fd00::cccc"));
1703 
1704     host.mHostName        = "myhost";
1705     host.mAddresses       = hostAddresses;
1706     host.mAddressesLength = 3;
1707     host.mTtl             = 1500;
1708 
1709     hostFullName.Append("%s.local.", host.mHostName);
1710 
1711     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1712     Log("Register a `HostEntry`, check probes and announcements");
1713 
1714     sDnsMessages.Clear();
1715 
1716     sRegCallbacks[0].Reset();
1717     SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
1718 
1719     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
1720     {
1721         sDnsMessages.Clear();
1722 
1723         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
1724         AdvanceTime(250);
1725 
1726         VerifyOrQuit(!sDnsMessages.IsEmpty());
1727         dnsMsg = sDnsMessages.GetHead();
1728         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 3, /* Addnl */ 0);
1729         dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ (probeCount == 0));
1730         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
1731     }
1732 
1733     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
1734     {
1735         sDnsMessages.Clear();
1736 
1737         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
1738         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
1739 
1740         VerifyOrQuit(!sDnsMessages.IsEmpty());
1741         dnsMsg = sDnsMessages.GetHead();
1742         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 1);
1743         dnsMsg->Validate(host, kInAnswerSection);
1744         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
1745     }
1746 
1747     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1748     Log("Send a query for AAAA record and validate the response");
1749 
1750     AdvanceTime(2000);
1751 
1752     sDnsMessages.Clear();
1753     SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeAaaa);
1754 
1755     AdvanceTime(1000);
1756 
1757     dnsMsg = sDnsMessages.GetHead();
1758     VerifyOrQuit(dnsMsg != nullptr);
1759     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 1);
1760     dnsMsg->Validate(host, kInAnswerSection);
1761 
1762     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1763     Log("Send a query for ANY record and validate the response");
1764 
1765     AdvanceTime(2000);
1766 
1767     sDnsMessages.Clear();
1768     SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeAny);
1769 
1770     AdvanceTime(1000);
1771 
1772     dnsMsg = sDnsMessages.GetHead();
1773     VerifyOrQuit(dnsMsg != nullptr);
1774     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 1);
1775     dnsMsg->Validate(host, kInAnswerSection);
1776 
1777     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1778     Log("Send a query for non-existing record and validate the response with NSEC");
1779 
1780     AdvanceTime(2000);
1781 
1782     sDnsMessages.Clear();
1783     SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeA);
1784 
1785     AdvanceTime(1000);
1786 
1787     dnsMsg = sDnsMessages.GetHead();
1788     VerifyOrQuit(dnsMsg != nullptr);
1789     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 1);
1790     VerifyOrQuit(dnsMsg->mAdditionalRecords.ContainsNsec(hostFullName, ResourceRecord::kTypeAaaa));
1791 
1792     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1793     Log("Update number of host addresses and validate new announcements");
1794 
1795     host.mAddressesLength = 2;
1796 
1797     sRegCallbacks[1].Reset();
1798     sDnsMessages.Clear();
1799     SuccessOrQuit(mdns->RegisterHost(host, 1, HandleSuccessCallback));
1800 
1801     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
1802     {
1803         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
1804         VerifyOrQuit(sRegCallbacks[1].mWasCalled);
1805 
1806         VerifyOrQuit(!sDnsMessages.IsEmpty());
1807         dnsMsg = sDnsMessages.GetHead();
1808         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
1809         dnsMsg->Validate(host, kInAnswerSection);
1810         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
1811         sDnsMessages.Clear();
1812     }
1813 
1814     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1815     Log("Change the addresses and validate the first announce");
1816 
1817     host.mAddressesLength = 3;
1818 
1819     sRegCallbacks[0].Reset();
1820     sDnsMessages.Clear();
1821     SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
1822 
1823     AdvanceTime(300);
1824     VerifyOrQuit(sRegCallbacks[0].mWasCalled);
1825 
1826     VerifyOrQuit(!sDnsMessages.IsEmpty());
1827     dnsMsg = sDnsMessages.GetHead();
1828     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 1);
1829     dnsMsg->Validate(host, kInAnswerSection);
1830     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
1831 
1832     Log("Change the address list again before second announce");
1833 
1834     host.mAddressesLength = 1;
1835 
1836     sRegCallbacks[1].Reset();
1837     sDnsMessages.Clear();
1838     SuccessOrQuit(mdns->RegisterHost(host, 1, HandleSuccessCallback));
1839 
1840     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
1841     {
1842         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
1843         VerifyOrQuit(sRegCallbacks[1].mWasCalled);
1844 
1845         VerifyOrQuit(!sDnsMessages.IsEmpty());
1846         dnsMsg = sDnsMessages.GetHead();
1847         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
1848         dnsMsg->Validate(host, kInAnswerSection);
1849         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
1850         sDnsMessages.Clear();
1851     }
1852 
1853     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1854     Log("Change `HostEntry` TTL and validate announcements");
1855 
1856     host.mTtl = 120;
1857 
1858     sRegCallbacks[1].Reset();
1859     sDnsMessages.Clear();
1860     SuccessOrQuit(mdns->RegisterHost(host, 1, HandleSuccessCallback));
1861 
1862     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
1863     {
1864         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
1865         VerifyOrQuit(sRegCallbacks[1].mWasCalled);
1866 
1867         VerifyOrQuit(!sDnsMessages.IsEmpty());
1868         dnsMsg = sDnsMessages.GetHead();
1869         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
1870         dnsMsg->Validate(host, kInAnswerSection);
1871         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
1872         sDnsMessages.Clear();
1873     }
1874 
1875     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1876     Log("Send a query for AAAA record and validate the response");
1877 
1878     AdvanceTime(2000);
1879 
1880     sDnsMessages.Clear();
1881     SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeAaaa);
1882 
1883     AdvanceTime(1000);
1884 
1885     dnsMsg = sDnsMessages.GetHead();
1886     VerifyOrQuit(dnsMsg != nullptr);
1887     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
1888     dnsMsg->Validate(host, kInAnswerSection);
1889 
1890     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1891     Log("Unregister the host and validate the goodbye announces");
1892 
1893     sDnsMessages.Clear();
1894     SuccessOrQuit(mdns->UnregisterHost(host));
1895 
1896     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
1897     {
1898         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
1899 
1900         VerifyOrQuit(!sDnsMessages.IsEmpty());
1901         dnsMsg = sDnsMessages.GetHead();
1902         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
1903         dnsMsg->Validate(host, kInAnswerSection, kGoodBye);
1904         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
1905         sDnsMessages.Clear();
1906     }
1907 
1908     AdvanceTime(15000);
1909     VerifyOrQuit(sDnsMessages.IsEmpty());
1910 
1911     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1912     Log("Register a host with no address (first time)");
1913 
1914     host.mHostName        = "newhost";
1915     host.mAddresses       = nullptr;
1916     host.mAddressesLength = 0;
1917     host.mTtl             = 1500;
1918 
1919     sRegCallbacks[2].Reset();
1920     SuccessOrQuit(mdns->RegisterHost(host, 2, HandleSuccessCallback));
1921 
1922     AdvanceTime(1);
1923     VerifyOrQuit(sRegCallbacks[2].mWasCalled);
1924 
1925     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1926     Log("Register the same host now with an address");
1927 
1928     host.mAddresses       = &hostAddresses[0];
1929     host.mAddressesLength = 1;
1930 
1931     sRegCallbacks[3].Reset();
1932     SuccessOrQuit(mdns->RegisterHost(host, 3, HandleSuccessCallback));
1933 
1934     AdvanceTime(15000);
1935     VerifyOrQuit(sRegCallbacks[3].mWasCalled);
1936 
1937     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1938     Log("Register the same host again now with no address");
1939 
1940     host.mAddressesLength = 0;
1941 
1942     sRegCallbacks[4].Reset();
1943     sDnsMessages.Clear();
1944     SuccessOrQuit(mdns->RegisterHost(host, 4, HandleSuccessCallback));
1945 
1946     AdvanceTime(1);
1947     VerifyOrQuit(sRegCallbacks[4].mWasCalled);
1948 
1949     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
1950     {
1951         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
1952 
1953         VerifyOrQuit(!sDnsMessages.IsEmpty());
1954         dnsMsg = sDnsMessages.GetHead();
1955         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
1956         dnsMsg->Validate(host, kInAnswerSection, kGoodBye);
1957         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
1958         sDnsMessages.Clear();
1959     }
1960 
1961     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1962     Log("Register the same host again now adding an address");
1963 
1964     host.mAddresses       = &hostAddresses[1];
1965     host.mAddressesLength = 1;
1966 
1967     sRegCallbacks[5].Reset();
1968     SuccessOrQuit(mdns->RegisterHost(host, 5, HandleSuccessCallback));
1969 
1970     AdvanceTime(15000);
1971     VerifyOrQuit(sRegCallbacks[5].mWasCalled);
1972 
1973     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1974 
1975     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
1976     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
1977 
1978     Log("End of test");
1979 
1980     testFreeInstance(sInstance);
1981 }
1982 
1983 //---------------------------------------------------------------------------------------------------------------------
1984 
TestKeyReg(void)1985 void TestKeyReg(void)
1986 {
1987     Core             *mdns = InitTest();
1988     Core::Key         key;
1989     const DnsMessage *dnsMsg;
1990     uint16_t          heapAllocations;
1991 
1992     Log("-------------------------------------------------------------------------------------------");
1993     Log("TestKeyReg");
1994 
1995     AdvanceTime(1);
1996 
1997     heapAllocations = sHeapAllocatedPtrs.GetLength();
1998     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
1999 
2000     // Run all tests twice. first with key for a host name, followed
2001     // by key for service instance name.
2002 
2003     for (uint8_t iter = 0; iter < 2; iter++)
2004     {
2005         DnsNameString fullName;
2006 
2007         if (iter == 0)
2008         {
2009             Log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
2010             Log("Registering key for 'myhost' host name");
2011             key.mName        = "myhost";
2012             key.mServiceType = nullptr;
2013 
2014             fullName.Append("%s.local.", key.mName);
2015         }
2016         else
2017         {
2018             Log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
2019             Log("Registering key for 'mysrv._srv._udo' service name");
2020 
2021             key.mName        = "mysrv";
2022             key.mServiceType = "_srv._udp";
2023 
2024             fullName.Append("%s.%s.local.", key.mName, key.mServiceType);
2025         }
2026 
2027         key.mKeyData       = kKey1;
2028         key.mKeyDataLength = sizeof(kKey1);
2029         key.mTtl           = 8000;
2030 
2031         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2032         Log("Register a key record and check probes and announcements");
2033 
2034         sDnsMessages.Clear();
2035 
2036         sRegCallbacks[0].Reset();
2037         SuccessOrQuit(mdns->RegisterKey(key, 0, HandleSuccessCallback));
2038 
2039         for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
2040         {
2041             sDnsMessages.Clear();
2042 
2043             VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
2044             AdvanceTime(250);
2045 
2046             VerifyOrQuit(!sDnsMessages.IsEmpty());
2047             dnsMsg = sDnsMessages.GetHead();
2048             dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 1, /* Addnl */ 0);
2049             dnsMsg->ValidateAsProbeFor(key, /* aUnicastRequest */ (probeCount == 0));
2050             VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2051         }
2052 
2053         for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2054         {
2055             sDnsMessages.Clear();
2056 
2057             AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
2058             VerifyOrQuit(sRegCallbacks[0].mWasCalled);
2059 
2060             VerifyOrQuit(!sDnsMessages.IsEmpty());
2061             dnsMsg = sDnsMessages.GetHead();
2062             dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
2063             dnsMsg->Validate(key, kInAnswerSection);
2064             VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2065         }
2066 
2067         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2068         Log("Send a query for KEY record and validate the response");
2069 
2070         AdvanceTime(2000);
2071 
2072         sDnsMessages.Clear();
2073         SendQuery(fullName.AsCString(), ResourceRecord::kTypeKey);
2074 
2075         AdvanceTime(1000);
2076 
2077         dnsMsg = sDnsMessages.GetHead();
2078         VerifyOrQuit(dnsMsg != nullptr);
2079         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
2080         dnsMsg->Validate(key, kInAnswerSection);
2081 
2082         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2083         Log("Send a query for ANY record and validate the response");
2084 
2085         AdvanceTime(2000);
2086 
2087         sDnsMessages.Clear();
2088         SendQuery(fullName.AsCString(), ResourceRecord::kTypeAny);
2089 
2090         AdvanceTime(1000);
2091 
2092         dnsMsg = sDnsMessages.GetHead();
2093         VerifyOrQuit(dnsMsg != nullptr);
2094         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
2095         dnsMsg->Validate(key, kInAnswerSection);
2096 
2097         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2098         Log("Send a query for non-existing record and validate the response with NSEC");
2099 
2100         AdvanceTime(2000);
2101 
2102         sDnsMessages.Clear();
2103         SendQuery(fullName.AsCString(), ResourceRecord::kTypeA);
2104 
2105         AdvanceTime(1000);
2106 
2107         dnsMsg = sDnsMessages.GetHead();
2108         VerifyOrQuit(dnsMsg != nullptr);
2109         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 1);
2110         VerifyOrQuit(dnsMsg->mAdditionalRecords.ContainsNsec(fullName, ResourceRecord::kTypeKey));
2111 
2112         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2113         Log("Change the TTL");
2114 
2115         key.mTtl = 0; // Use default
2116 
2117         sRegCallbacks[1].Reset();
2118         sDnsMessages.Clear();
2119         SuccessOrQuit(mdns->RegisterKey(key, 1, HandleSuccessCallback));
2120 
2121         for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2122         {
2123             AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
2124             VerifyOrQuit(sRegCallbacks[1].mWasCalled);
2125 
2126             VerifyOrQuit(!sDnsMessages.IsEmpty());
2127             dnsMsg = sDnsMessages.GetHead();
2128             dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
2129             dnsMsg->Validate(key, kInAnswerSection);
2130             VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2131 
2132             sDnsMessages.Clear();
2133         }
2134 
2135         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2136         Log("Change the key");
2137 
2138         key.mKeyData       = kKey2;
2139         key.mKeyDataLength = sizeof(kKey2);
2140 
2141         sRegCallbacks[1].Reset();
2142         sDnsMessages.Clear();
2143         SuccessOrQuit(mdns->RegisterKey(key, 1, HandleSuccessCallback));
2144 
2145         for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2146         {
2147             AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
2148             VerifyOrQuit(sRegCallbacks[1].mWasCalled);
2149 
2150             VerifyOrQuit(!sDnsMessages.IsEmpty());
2151             dnsMsg = sDnsMessages.GetHead();
2152             dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
2153             dnsMsg->Validate(key, kInAnswerSection);
2154             VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2155 
2156             sDnsMessages.Clear();
2157         }
2158 
2159         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2160         Log("Unregister the key and validate the goodbye announces");
2161 
2162         sDnsMessages.Clear();
2163         SuccessOrQuit(mdns->UnregisterKey(key));
2164 
2165         for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2166         {
2167             AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
2168 
2169             VerifyOrQuit(!sDnsMessages.IsEmpty());
2170             dnsMsg = sDnsMessages.GetHead();
2171             dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
2172             dnsMsg->Validate(key, kInAnswerSection, kGoodBye);
2173             VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2174 
2175             sDnsMessages.Clear();
2176         }
2177     }
2178 
2179     AdvanceTime(15000);
2180     VerifyOrQuit(sDnsMessages.IsEmpty());
2181 
2182     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
2183     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
2184 
2185     Log("End of test");
2186 
2187     testFreeInstance(sInstance);
2188 }
2189 
2190 //---------------------------------------------------------------------------------------------------------------------
2191 
TestServiceReg(void)2192 void TestServiceReg(void)
2193 {
2194     Core             *mdns = InitTest();
2195     Core::Service     service;
2196     const DnsMessage *dnsMsg;
2197     uint16_t          heapAllocations;
2198     DnsNameString     fullServiceName;
2199     DnsNameString     fullServiceType;
2200 
2201     Log("-------------------------------------------------------------------------------------------");
2202     Log("TestServiceReg");
2203 
2204     AdvanceTime(1);
2205 
2206     heapAllocations = sHeapAllocatedPtrs.GetLength();
2207     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
2208 
2209     service.mHostName            = "myhost";
2210     service.mServiceInstance     = "myservice";
2211     service.mServiceType         = "_srv._udp";
2212     service.mSubTypeLabels       = nullptr;
2213     service.mSubTypeLabelsLength = 0;
2214     service.mTxtData             = kTxtData1;
2215     service.mTxtDataLength       = sizeof(kTxtData1);
2216     service.mPort                = 1234;
2217     service.mPriority            = 1;
2218     service.mWeight              = 2;
2219     service.mTtl                 = 1000;
2220 
2221     fullServiceName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
2222     fullServiceType.Append("%s.local.", service.mServiceType);
2223 
2224     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2225     Log("Register a `ServiceEntry`, check probes and announcements");
2226 
2227     sDnsMessages.Clear();
2228 
2229     sRegCallbacks[0].Reset();
2230     SuccessOrQuit(mdns->RegisterService(service, 0, HandleSuccessCallback));
2231 
2232     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
2233     {
2234         sDnsMessages.Clear();
2235 
2236         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
2237         AdvanceTime(250);
2238 
2239         VerifyOrQuit(!sDnsMessages.IsEmpty());
2240         dnsMsg = sDnsMessages.GetHead();
2241         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
2242         dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ (probeCount == 0));
2243         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2244     }
2245 
2246     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2247     {
2248         sDnsMessages.Clear();
2249 
2250         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
2251         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
2252 
2253         VerifyOrQuit(!sDnsMessages.IsEmpty());
2254         dnsMsg = sDnsMessages.GetHead();
2255         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
2256         dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
2257         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2258     }
2259 
2260     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2261     Log("Send a query for SRV record and validate the response");
2262 
2263     AdvanceTime(2000);
2264 
2265     sDnsMessages.Clear();
2266     SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeSrv);
2267 
2268     AdvanceTime(1000);
2269 
2270     dnsMsg = sDnsMessages.GetHead();
2271     VerifyOrQuit(dnsMsg != nullptr);
2272     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
2273     dnsMsg->Validate(service, kInAnswerSection, kCheckSrv);
2274 
2275     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2276     Log("Send a query for TXT record and validate the response");
2277 
2278     AdvanceTime(2000);
2279 
2280     sDnsMessages.Clear();
2281     SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeTxt);
2282 
2283     AdvanceTime(1000);
2284 
2285     dnsMsg = sDnsMessages.GetHead();
2286     VerifyOrQuit(dnsMsg != nullptr);
2287     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
2288     dnsMsg->Validate(service, kInAnswerSection, kCheckTxt);
2289 
2290     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2291     Log("Send a query for ANY record and validate the response");
2292 
2293     AdvanceTime(2000);
2294 
2295     sDnsMessages.Clear();
2296     SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeAny);
2297 
2298     AdvanceTime(1000);
2299 
2300     dnsMsg = sDnsMessages.GetHead();
2301     VerifyOrQuit(dnsMsg != nullptr);
2302     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
2303     dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt);
2304 
2305     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2306     Log("Send a query for PTR record for service type and validate the response");
2307 
2308     AdvanceTime(2000);
2309 
2310     sDnsMessages.Clear();
2311     SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr);
2312 
2313     AdvanceTime(1000);
2314 
2315     dnsMsg = sDnsMessages.GetHead();
2316     VerifyOrQuit(dnsMsg != nullptr);
2317     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 2);
2318     dnsMsg->Validate(service, kInAnswerSection, kCheckPtr);
2319     dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
2320 
2321     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2322     Log("Send a query for PTR record for `services._dns-sd` and validate the response");
2323 
2324     AdvanceTime(2000);
2325 
2326     sDnsMessages.Clear();
2327     SendQuery("_services._dns-sd._udp.local.", ResourceRecord::kTypePtr);
2328 
2329     AdvanceTime(1000);
2330 
2331     dnsMsg = sDnsMessages.GetHead();
2332     VerifyOrQuit(dnsMsg != nullptr);
2333     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
2334     dnsMsg->Validate(service, kInAnswerSection, kCheckServicesPtr);
2335 
2336     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2337     Log("Update service port number and validate new announcements of SRV record");
2338 
2339     service.mPort = 4567;
2340 
2341     sRegCallbacks[1].Reset();
2342     sDnsMessages.Clear();
2343     SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
2344 
2345     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2346     {
2347         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
2348         VerifyOrQuit(sRegCallbacks[1].mWasCalled);
2349 
2350         VerifyOrQuit(!sDnsMessages.IsEmpty());
2351         dnsMsg = sDnsMessages.GetHead();
2352         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
2353         dnsMsg->Validate(service, kInAnswerSection, kCheckSrv);
2354         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2355         sDnsMessages.Clear();
2356     }
2357 
2358     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2359     Log("Update TXT data and validate new announcements of TXT record");
2360 
2361     service.mTxtData       = nullptr;
2362     service.mTxtDataLength = 0;
2363 
2364     sRegCallbacks[1].Reset();
2365     sDnsMessages.Clear();
2366     SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
2367 
2368     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2369     {
2370         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
2371         VerifyOrQuit(sRegCallbacks[1].mWasCalled);
2372 
2373         VerifyOrQuit(!sDnsMessages.IsEmpty());
2374         dnsMsg = sDnsMessages.GetHead();
2375         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
2376         dnsMsg->Validate(service, kInAnswerSection, kCheckTxt);
2377         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2378         sDnsMessages.Clear();
2379     }
2380 
2381     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2382     Log("Update both service and TXT data and validate new announcements of both records");
2383 
2384     service.mTxtData       = kTxtData2;
2385     service.mTxtDataLength = sizeof(kTxtData2);
2386     service.mWeight        = 0;
2387 
2388     sRegCallbacks[1].Reset();
2389     sDnsMessages.Clear();
2390     SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
2391 
2392     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2393     {
2394         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
2395         VerifyOrQuit(sRegCallbacks[1].mWasCalled);
2396 
2397         VerifyOrQuit(!sDnsMessages.IsEmpty());
2398         dnsMsg = sDnsMessages.GetHead();
2399         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
2400         dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt);
2401         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2402         sDnsMessages.Clear();
2403     }
2404 
2405     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2406     Log("Update service host name and validate new announcements of SRV record");
2407 
2408     service.mHostName = "newhost";
2409 
2410     sRegCallbacks[1].Reset();
2411     sDnsMessages.Clear();
2412     SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
2413 
2414     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2415     {
2416         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
2417         VerifyOrQuit(sRegCallbacks[1].mWasCalled);
2418 
2419         VerifyOrQuit(!sDnsMessages.IsEmpty());
2420         dnsMsg = sDnsMessages.GetHead();
2421         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
2422         dnsMsg->Validate(service, kInAnswerSection, kCheckSrv);
2423         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2424         sDnsMessages.Clear();
2425     }
2426 
2427     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2428     Log("Update TTL and validate new announcements of SRV, TXT and PTR records");
2429 
2430     service.mTtl = 0;
2431 
2432     sRegCallbacks[1].Reset();
2433     sDnsMessages.Clear();
2434     SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
2435 
2436     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2437     {
2438         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
2439         VerifyOrQuit(sRegCallbacks[1].mWasCalled);
2440 
2441         VerifyOrQuit(!sDnsMessages.IsEmpty());
2442         dnsMsg = sDnsMessages.GetHead();
2443         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 1);
2444         dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr);
2445         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2446         sDnsMessages.Clear();
2447     }
2448 
2449     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2450     Log("Unregister the service and validate the goodbye announces");
2451 
2452     sDnsMessages.Clear();
2453     SuccessOrQuit(mdns->UnregisterService(service));
2454 
2455     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2456     {
2457         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
2458 
2459         VerifyOrQuit(!sDnsMessages.IsEmpty());
2460         dnsMsg = sDnsMessages.GetHead();
2461         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 0);
2462         dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr, kGoodBye);
2463         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2464         sDnsMessages.Clear();
2465     }
2466 
2467     AdvanceTime(15000);
2468     VerifyOrQuit(sDnsMessages.IsEmpty());
2469 
2470     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
2471     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
2472 
2473     Log("End of test");
2474 
2475     testFreeInstance(sInstance);
2476 }
2477 
2478 //---------------------------------------------------------------------------------------------------------------------
2479 
TestUnregisterBeforeProbeFinished(void)2480 void TestUnregisterBeforeProbeFinished(void)
2481 {
2482     const uint8_t kKey1[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
2483 
2484     Core             *mdns = InitTest();
2485     Core::Host        host;
2486     Core::Service     service;
2487     Core::Key         key;
2488     Ip6::Address      hostAddresses[3];
2489     const DnsMessage *dnsMsg;
2490     uint16_t          heapAllocations;
2491 
2492     Log("-------------------------------------------------------------------------------------------");
2493     Log("TestUnregisterBeforeProbeFinished");
2494 
2495     AdvanceTime(1);
2496 
2497     heapAllocations = sHeapAllocatedPtrs.GetLength();
2498     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
2499 
2500     SuccessOrQuit(hostAddresses[0].FromString("fd00::aaaa"));
2501     SuccessOrQuit(hostAddresses[1].FromString("fd00::bbbb"));
2502     SuccessOrQuit(hostAddresses[2].FromString("fd00::cccc"));
2503 
2504     host.mHostName        = "myhost";
2505     host.mAddresses       = hostAddresses;
2506     host.mAddressesLength = 3;
2507     host.mTtl             = 1500;
2508 
2509     service.mHostName            = "myhost";
2510     service.mServiceInstance     = "myservice";
2511     service.mServiceType         = "_srv._udp";
2512     service.mSubTypeLabels       = nullptr;
2513     service.mSubTypeLabelsLength = 0;
2514     service.mTxtData             = kTxtData1;
2515     service.mTxtDataLength       = sizeof(kTxtData1);
2516     service.mPort                = 1234;
2517     service.mPriority            = 1;
2518     service.mWeight              = 2;
2519     service.mTtl                 = 1000;
2520 
2521     key.mName          = "mysrv";
2522     key.mServiceType   = "_srv._udp";
2523     key.mKeyData       = kKey1;
2524     key.mKeyDataLength = sizeof(kKey1);
2525     key.mTtl           = 8000;
2526 
2527     // Repeat the same test 3 times for host and service and key registration.
2528 
2529     for (uint8_t iter = 0; iter < 3; iter++)
2530     {
2531         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2532         Log("Register an entry, check for the first two probes");
2533 
2534         sDnsMessages.Clear();
2535 
2536         sRegCallbacks[0].Reset();
2537 
2538         switch (iter)
2539         {
2540         case 0:
2541             SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
2542             break;
2543         case 1:
2544             SuccessOrQuit(mdns->RegisterService(service, 0, HandleSuccessCallback));
2545             break;
2546         case 2:
2547             SuccessOrQuit(mdns->RegisterKey(key, 0, HandleSuccessCallback));
2548             break;
2549         }
2550 
2551         for (uint8_t probeCount = 0; probeCount < 2; probeCount++)
2552         {
2553             sDnsMessages.Clear();
2554 
2555             VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
2556             AdvanceTime(250);
2557 
2558             VerifyOrQuit(!sDnsMessages.IsEmpty());
2559             dnsMsg = sDnsMessages.GetHead();
2560 
2561             switch (iter)
2562             {
2563             case 0:
2564                 dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 3, /* Addnl */ 0);
2565                 dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ (probeCount == 0));
2566                 break;
2567             case 1:
2568                 dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
2569                 dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ (probeCount == 0));
2570                 break;
2571             case 2:
2572                 dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 1, /* Addnl */ 0);
2573                 dnsMsg->ValidateAsProbeFor(key, /* aUnicastRequest */ (probeCount == 0));
2574                 break;
2575             }
2576 
2577             VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2578         }
2579 
2580         sDnsMessages.Clear();
2581         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
2582 
2583         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2584         Log("Unregister the entry before the last probe and make sure probing stops");
2585 
2586         switch (iter)
2587         {
2588         case 0:
2589             SuccessOrQuit(mdns->UnregisterHost(host));
2590             break;
2591         case 1:
2592             SuccessOrQuit(mdns->UnregisterService(service));
2593             break;
2594         case 2:
2595             SuccessOrQuit(mdns->UnregisterKey(key));
2596             break;
2597         }
2598 
2599         AdvanceTime(20 * 1000);
2600         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
2601 
2602         VerifyOrQuit(sDnsMessages.IsEmpty());
2603     }
2604 
2605     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
2606     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
2607 
2608     Log("End of test");
2609 
2610     testFreeInstance(sInstance);
2611 }
2612 
2613 //---------------------------------------------------------------------------------------------------------------------
2614 
TestServiceSubTypeReg(void)2615 void TestServiceSubTypeReg(void)
2616 {
2617     static const char *const kSubTypes1[] = {"_s1", "_r2", "_vXy", "_last"};
2618     static const char *const kSubTypes2[] = {"_vxy", "_r1", "_r2", "_zzz"};
2619 
2620     Core             *mdns = InitTest();
2621     Core::Service     service;
2622     const DnsMessage *dnsMsg;
2623     uint16_t          heapAllocations;
2624     DnsNameString     fullServiceName;
2625     DnsNameString     fullServiceType;
2626     DnsNameString     fullSubServiceType;
2627 
2628     Log("-------------------------------------------------------------------------------------------");
2629     Log("TestServiceSubTypeReg");
2630 
2631     AdvanceTime(1);
2632 
2633     heapAllocations = sHeapAllocatedPtrs.GetLength();
2634     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
2635 
2636     service.mHostName            = "tarnished";
2637     service.mServiceInstance     = "elden";
2638     service.mServiceType         = "_ring._udp";
2639     service.mSubTypeLabels       = kSubTypes1;
2640     service.mSubTypeLabelsLength = 3;
2641     service.mTxtData             = kTxtData1;
2642     service.mTxtDataLength       = sizeof(kTxtData1);
2643     service.mPort                = 1234;
2644     service.mPriority            = 1;
2645     service.mWeight              = 2;
2646     service.mTtl                 = 6000;
2647 
2648     fullServiceName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
2649     fullServiceType.Append("%s.local.", service.mServiceType);
2650 
2651     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2652     Log("Register a `ServiceEntry` with sub-types, check probes and announcements");
2653 
2654     sDnsMessages.Clear();
2655 
2656     sRegCallbacks[0].Reset();
2657     SuccessOrQuit(mdns->RegisterService(service, 0, HandleSuccessCallback));
2658 
2659     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
2660     {
2661         sDnsMessages.Clear();
2662 
2663         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
2664         AdvanceTime(250);
2665 
2666         VerifyOrQuit(!sDnsMessages.IsEmpty());
2667         dnsMsg = sDnsMessages.GetHead();
2668         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
2669         dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ (probeCount == 0));
2670         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2671     }
2672 
2673     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2674     {
2675         sDnsMessages.Clear();
2676 
2677         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
2678         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
2679 
2680         VerifyOrQuit(!sDnsMessages.IsEmpty());
2681         dnsMsg = sDnsMessages.GetHead();
2682         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 7, /* Auth */ 0, /* Addnl */ 1);
2683         dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
2684 
2685         for (uint16_t index = 0; index < service.mSubTypeLabelsLength; index++)
2686         {
2687             dnsMsg->ValidateSubType(service.mSubTypeLabels[index], service);
2688         }
2689 
2690         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2691     }
2692 
2693     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2694     Log("Send a query for SRV record and validate the response");
2695 
2696     AdvanceTime(2000);
2697 
2698     sDnsMessages.Clear();
2699     SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeSrv);
2700 
2701     AdvanceTime(1000);
2702 
2703     dnsMsg = sDnsMessages.GetHead();
2704     VerifyOrQuit(dnsMsg != nullptr);
2705     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
2706     dnsMsg->Validate(service, kInAnswerSection, kCheckSrv);
2707 
2708     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2709     Log("Send a query for TXT record and validate the response");
2710 
2711     AdvanceTime(2000);
2712 
2713     sDnsMessages.Clear();
2714     SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeTxt);
2715 
2716     AdvanceTime(1000);
2717 
2718     dnsMsg = sDnsMessages.GetHead();
2719     VerifyOrQuit(dnsMsg != nullptr);
2720     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
2721     dnsMsg->Validate(service, kInAnswerSection, kCheckTxt);
2722 
2723     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2724     Log("Send a query for ANY record and validate the response");
2725 
2726     AdvanceTime(2000);
2727 
2728     sDnsMessages.Clear();
2729     SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeAny);
2730 
2731     AdvanceTime(1000);
2732 
2733     dnsMsg = sDnsMessages.GetHead();
2734     VerifyOrQuit(dnsMsg != nullptr);
2735     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
2736     dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt);
2737 
2738     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2739     Log("Send a query for PTR record for service type and validate the response");
2740 
2741     AdvanceTime(2000);
2742 
2743     sDnsMessages.Clear();
2744     SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr);
2745 
2746     AdvanceTime(1000);
2747 
2748     dnsMsg = sDnsMessages.GetHead();
2749     VerifyOrQuit(dnsMsg != nullptr);
2750     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 2);
2751     dnsMsg->Validate(service, kInAnswerSection, kCheckPtr);
2752     dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
2753 
2754     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2755     Log("Send a query for PTR record for `services._dns-sd` and validate the response");
2756 
2757     AdvanceTime(2000);
2758 
2759     sDnsMessages.Clear();
2760     SendQuery("_services._dns-sd._udp.local.", ResourceRecord::kTypePtr);
2761 
2762     AdvanceTime(1000);
2763 
2764     dnsMsg = sDnsMessages.GetHead();
2765     VerifyOrQuit(dnsMsg != nullptr);
2766     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
2767     dnsMsg->Validate(service, kInAnswerSection, kCheckServicesPtr);
2768 
2769     for (uint16_t index = 0; index < service.mSubTypeLabelsLength; index++)
2770     {
2771         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2772         Log("Send a PTR query for sub-type `%s` and validate the response", service.mSubTypeLabels[index]);
2773 
2774         fullSubServiceType.Clear();
2775         fullSubServiceType.Append("%s._sub.%s", service.mSubTypeLabels[index], fullServiceType.AsCString());
2776 
2777         AdvanceTime(2000);
2778 
2779         sDnsMessages.Clear();
2780         SendQuery(fullSubServiceType.AsCString(), ResourceRecord::kTypePtr);
2781 
2782         AdvanceTime(1000);
2783 
2784         dnsMsg = sDnsMessages.GetHead();
2785         VerifyOrQuit(dnsMsg != nullptr);
2786         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 2);
2787         dnsMsg->ValidateSubType(service.mSubTypeLabels[index], service);
2788         dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
2789     }
2790 
2791     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2792     Log("Send a PTR query for non-existing sub-type and validate there is no response");
2793 
2794     AdvanceTime(2000);
2795 
2796     fullSubServiceType.Clear();
2797     fullSubServiceType.Append("_none._sub.%s", fullServiceType.AsCString());
2798 
2799     sDnsMessages.Clear();
2800     SendQuery(fullSubServiceType.AsCString(), ResourceRecord::kTypePtr);
2801 
2802     AdvanceTime(2000);
2803     VerifyOrQuit(sDnsMessages.IsEmpty());
2804 
2805     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2806     Log("Register a new sub-type and validate announcements of PTR record for it");
2807 
2808     service.mSubTypeLabelsLength = 4;
2809 
2810     sRegCallbacks[1].Reset();
2811     sDnsMessages.Clear();
2812     SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
2813 
2814     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2815     {
2816         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
2817         VerifyOrQuit(sRegCallbacks[1].mWasCalled);
2818 
2819         VerifyOrQuit(!sDnsMessages.IsEmpty());
2820         dnsMsg = sDnsMessages.GetHead();
2821         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 2);
2822         dnsMsg->ValidateSubType(service.mSubTypeLabels[3], service);
2823         dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
2824         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2825         sDnsMessages.Clear();
2826     }
2827 
2828     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2829     Log("Remove a previous sub-type and validate announcements of its removal");
2830 
2831     service.mSubTypeLabels++;
2832     service.mSubTypeLabelsLength = 3;
2833 
2834     sRegCallbacks[1].Reset();
2835     sDnsMessages.Clear();
2836     SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
2837 
2838     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2839     {
2840         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
2841         VerifyOrQuit(sRegCallbacks[1].mWasCalled);
2842 
2843         VerifyOrQuit(!sDnsMessages.IsEmpty());
2844         dnsMsg = sDnsMessages.GetHead();
2845         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
2846         dnsMsg->ValidateSubType(kSubTypes1[0], service, kGoodBye);
2847         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2848         sDnsMessages.Clear();
2849     }
2850 
2851     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2852     Log("Update TTL and validate announcement of all records");
2853 
2854     service.mTtl = 0;
2855 
2856     sRegCallbacks[1].Reset();
2857     sDnsMessages.Clear();
2858     SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
2859 
2860     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2861     {
2862         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
2863         VerifyOrQuit(sRegCallbacks[1].mWasCalled);
2864 
2865         VerifyOrQuit(!sDnsMessages.IsEmpty());
2866         dnsMsg = sDnsMessages.GetHead();
2867         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 6, /* Auth */ 0, /* Addnl */ 1);
2868         dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr);
2869 
2870         for (uint16_t index = 0; index < service.mSubTypeLabelsLength; index++)
2871         {
2872             dnsMsg->ValidateSubType(service.mSubTypeLabels[index], service);
2873         }
2874 
2875         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2876         sDnsMessages.Clear();
2877     }
2878 
2879     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2880     Log("Add and remove sub-types at the same time and check proper announcements");
2881 
2882     // Registered sub-types: _r2, _vXy, _last
2883     // New sub-types list  : _vxy, _r1, _r2, _zzz
2884     //
2885     // Should announce removal of `_last` and addition of
2886     // `_r1` and `_zzz`. The `_vxy` should match with `_vXy`.
2887 
2888     service.mSubTypeLabels       = kSubTypes2;
2889     service.mSubTypeLabelsLength = 4;
2890 
2891     sRegCallbacks[1].Reset();
2892     sDnsMessages.Clear();
2893     SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
2894 
2895     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2896     {
2897         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
2898         VerifyOrQuit(sRegCallbacks[1].mWasCalled);
2899 
2900         VerifyOrQuit(!sDnsMessages.IsEmpty());
2901         dnsMsg = sDnsMessages.GetHead();
2902         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 2);
2903 
2904         dnsMsg->ValidateSubType(kSubTypes1[3], service, kGoodBye);
2905         dnsMsg->ValidateSubType(kSubTypes2[1], service);
2906         dnsMsg->ValidateSubType(kSubTypes2[3], service);
2907         dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
2908 
2909         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2910         sDnsMessages.Clear();
2911     }
2912 
2913     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
2914     Log("Unregister the service and validate the goodbye announces for service and its sub-types");
2915 
2916     sDnsMessages.Clear();
2917     SuccessOrQuit(mdns->UnregisterService(service));
2918 
2919     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
2920     {
2921         AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
2922 
2923         VerifyOrQuit(!sDnsMessages.IsEmpty());
2924         dnsMsg = sDnsMessages.GetHead();
2925         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 7, /* Auth */ 0, /* Addnl */ 0);
2926         dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr, kGoodBye);
2927 
2928         for (uint16_t index = 0; index < service.mSubTypeLabelsLength; index++)
2929         {
2930             dnsMsg->ValidateSubType(service.mSubTypeLabels[index], service, kGoodBye);
2931         }
2932 
2933         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
2934         sDnsMessages.Clear();
2935     }
2936 
2937     AdvanceTime(15000);
2938     VerifyOrQuit(sDnsMessages.IsEmpty());
2939 
2940     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
2941     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
2942 
2943     Log("End of test");
2944 
2945     testFreeInstance(sInstance);
2946 }
2947 
TestHostOrServiceAndKeyReg(void)2948 void TestHostOrServiceAndKeyReg(void)
2949 {
2950     Core             *mdns = InitTest();
2951     Core::Host        host;
2952     Core::Service     service;
2953     Core::Key         key;
2954     Ip6::Address      hostAddresses[2];
2955     const DnsMessage *dnsMsg;
2956     uint16_t          heapAllocations;
2957 
2958     Log("-------------------------------------------------------------------------------------------");
2959     Log("TestHostOrServiceAndKeyReg");
2960 
2961     AdvanceTime(1);
2962 
2963     heapAllocations = sHeapAllocatedPtrs.GetLength();
2964     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
2965 
2966     SuccessOrQuit(hostAddresses[0].FromString("fd00::1"));
2967     SuccessOrQuit(hostAddresses[1].FromString("fd00::2"));
2968 
2969     host.mHostName        = "myhost";
2970     host.mAddresses       = hostAddresses;
2971     host.mAddressesLength = 2;
2972     host.mTtl             = 5000;
2973 
2974     key.mKeyData       = kKey1;
2975     key.mKeyDataLength = sizeof(kKey1);
2976     key.mTtl           = 80000;
2977 
2978     service.mHostName            = "myhost";
2979     service.mServiceInstance     = "myservice";
2980     service.mServiceType         = "_srv._udp";
2981     service.mSubTypeLabels       = nullptr;
2982     service.mSubTypeLabelsLength = 0;
2983     service.mTxtData             = kTxtData1;
2984     service.mTxtDataLength       = sizeof(kTxtData1);
2985     service.mPort                = 1234;
2986     service.mPriority            = 1;
2987     service.mWeight              = 2;
2988     service.mTtl                 = 1000;
2989 
2990     // Run all test step twice, first time registering host and key,
2991     // second time registering service and key.
2992 
2993     for (uint8_t iter = 0; iter < 2; iter++)
2994     {
2995         if (iter == 0)
2996         {
2997             key.mName        = host.mHostName;
2998             key.mServiceType = nullptr;
2999         }
3000         else
3001         {
3002             key.mName        = service.mServiceInstance;
3003             key.mServiceType = service.mServiceType;
3004         }
3005 
3006         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3007         Log("Register a %s entry, check the first probe is sent", iter == 0 ? "host" : "service");
3008 
3009         sDnsMessages.Clear();
3010 
3011         sRegCallbacks[0].Reset();
3012 
3013         if (iter == 0)
3014         {
3015             SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
3016         }
3017         else
3018         {
3019             SuccessOrQuit(mdns->RegisterService(service, 0, HandleSuccessCallback));
3020         }
3021 
3022         sDnsMessages.Clear();
3023 
3024         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
3025         AdvanceTime(250);
3026 
3027         VerifyOrQuit(!sDnsMessages.IsEmpty());
3028         dnsMsg = sDnsMessages.GetHead();
3029 
3030         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
3031 
3032         if (iter == 0)
3033         {
3034             dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ true);
3035         }
3036         else
3037         {
3038             dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ true);
3039         }
3040 
3041         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3042 
3043         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3044         Log("Register a `KeyEntry` for same name, check that probes continue");
3045 
3046         sRegCallbacks[1].Reset();
3047         SuccessOrQuit(mdns->RegisterKey(key, 1, HandleSuccessCallback));
3048 
3049         for (uint8_t probeCount = 1; probeCount < 3; probeCount++)
3050         {
3051             sDnsMessages.Clear();
3052 
3053             VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
3054             VerifyOrQuit(!sRegCallbacks[1].mWasCalled);
3055 
3056             AdvanceTime(250);
3057 
3058             VerifyOrQuit(!sDnsMessages.IsEmpty());
3059             dnsMsg = sDnsMessages.GetHead();
3060             dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 3, /* Addnl */ 0);
3061 
3062             if (iter == 0)
3063             {
3064                 dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ false);
3065             }
3066             else
3067             {
3068                 dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ false);
3069             }
3070 
3071             dnsMsg->ValidateAsProbeFor(key, /* aUnicastRequest */ (probeCount == 0));
3072             VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3073         }
3074 
3075         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3076         Log("Validate Announces for both entry and key");
3077 
3078         for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
3079         {
3080             sDnsMessages.Clear();
3081 
3082             AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
3083             VerifyOrQuit(sRegCallbacks[0].mWasCalled);
3084             VerifyOrQuit(sRegCallbacks[1].mWasCalled);
3085 
3086             VerifyOrQuit(!sDnsMessages.IsEmpty());
3087             dnsMsg = sDnsMessages.GetHead();
3088 
3089             if (iter == 0)
3090             {
3091                 dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 1);
3092                 dnsMsg->Validate(host, kInAnswerSection);
3093             }
3094             else
3095             {
3096                 dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 5, /* Auth */ 0, /* Addnl */ 1);
3097                 dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
3098             }
3099 
3100             dnsMsg->Validate(key, kInAnswerSection);
3101             VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3102         }
3103 
3104         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3105         Log("Unregister the entry and validate its goodbye announces");
3106 
3107         sDnsMessages.Clear();
3108 
3109         if (iter == 0)
3110         {
3111             SuccessOrQuit(mdns->UnregisterHost(host));
3112         }
3113         else
3114         {
3115             SuccessOrQuit(mdns->UnregisterService(service));
3116         }
3117 
3118         for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
3119         {
3120             AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
3121 
3122             VerifyOrQuit(!sDnsMessages.IsEmpty());
3123             dnsMsg = sDnsMessages.GetHead();
3124 
3125             if (iter == 0)
3126             {
3127                 dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
3128                 dnsMsg->Validate(host, kInAnswerSection, kGoodBye);
3129             }
3130             else
3131             {
3132                 dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 1);
3133                 dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr, kGoodBye);
3134             }
3135 
3136             VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3137             sDnsMessages.Clear();
3138         }
3139 
3140         AdvanceTime(15000);
3141         VerifyOrQuit(sDnsMessages.IsEmpty());
3142 
3143         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3144         Log("Register the entry again, validate its announcements");
3145 
3146         sDnsMessages.Clear();
3147 
3148         sRegCallbacks[2].Reset();
3149 
3150         if (iter == 0)
3151         {
3152             SuccessOrQuit(mdns->RegisterHost(host, 2, HandleSuccessCallback));
3153         }
3154         else
3155         {
3156             SuccessOrQuit(mdns->RegisterService(service, 2, HandleSuccessCallback));
3157         }
3158 
3159         for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
3160         {
3161             sDnsMessages.Clear();
3162 
3163             AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
3164             VerifyOrQuit(sRegCallbacks[2].mWasCalled);
3165 
3166             VerifyOrQuit(!sDnsMessages.IsEmpty());
3167             dnsMsg = sDnsMessages.GetHead();
3168 
3169             if (iter == 0)
3170             {
3171                 dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
3172                 dnsMsg->Validate(host, kInAnswerSection);
3173             }
3174             else
3175             {
3176                 dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
3177                 dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
3178             }
3179 
3180             VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3181         }
3182 
3183         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3184         Log("Unregister the key and validate its goodbye announcements");
3185 
3186         sDnsMessages.Clear();
3187         SuccessOrQuit(mdns->UnregisterKey(key));
3188 
3189         for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
3190         {
3191             AdvanceTime((anncCount == 0) ? 0 : (1U << (anncCount - 1)) * 1000);
3192 
3193             VerifyOrQuit(!sDnsMessages.IsEmpty());
3194             dnsMsg = sDnsMessages.GetHead();
3195             dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
3196             dnsMsg->Validate(key, kInAnswerSection, kGoodBye);
3197             VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3198             sDnsMessages.Clear();
3199         }
3200 
3201         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3202         Log("Register the key again, validate its announcements");
3203 
3204         sDnsMessages.Clear();
3205 
3206         sRegCallbacks[3].Reset();
3207         SuccessOrQuit(mdns->RegisterKey(key, 3, HandleSuccessCallback));
3208 
3209         for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
3210         {
3211             sDnsMessages.Clear();
3212 
3213             AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
3214             VerifyOrQuit(sRegCallbacks[3].mWasCalled);
3215 
3216             VerifyOrQuit(!sDnsMessages.IsEmpty());
3217             dnsMsg = sDnsMessages.GetHead();
3218             dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
3219             dnsMsg->Validate(key, kInAnswerSection);
3220             VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3221         }
3222 
3223         sDnsMessages.Clear();
3224         AdvanceTime(15000);
3225         VerifyOrQuit(sDnsMessages.IsEmpty());
3226 
3227         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3228         Log("Unregister key first, validate two of its goodbye announcements");
3229 
3230         sDnsMessages.Clear();
3231 
3232         SuccessOrQuit(mdns->UnregisterKey(key));
3233 
3234         for (uint8_t anncCount = 0; anncCount < 2; anncCount++)
3235         {
3236             sDnsMessages.Clear();
3237 
3238             AdvanceTime((anncCount == 0) ? 1 : (1U << (anncCount - 1)) * 1000);
3239 
3240             VerifyOrQuit(!sDnsMessages.IsEmpty());
3241             dnsMsg = sDnsMessages.GetHead();
3242             dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
3243             dnsMsg->Validate(key, kInAnswerSection, kGoodBye);
3244             VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3245         }
3246 
3247         Log("Unregister entry as well");
3248 
3249         if (iter == 0)
3250         {
3251             SuccessOrQuit(mdns->UnregisterHost(host));
3252         }
3253         else
3254         {
3255             SuccessOrQuit(mdns->UnregisterService(service));
3256         }
3257 
3258         AdvanceTime(15000);
3259 
3260         for (uint16_t anncCount = 0; anncCount < 4; anncCount++)
3261         {
3262             dnsMsg = dnsMsg->GetNext();
3263             VerifyOrQuit(dnsMsg != nullptr);
3264 
3265             if (anncCount == 2)
3266             {
3267                 dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
3268                 dnsMsg->Validate(key, kInAnswerSection, kGoodBye);
3269             }
3270             else if (iter == 0)
3271             {
3272                 dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 0);
3273                 dnsMsg->Validate(host, kInAnswerSection, kGoodBye);
3274             }
3275             else
3276             {
3277                 dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 3, /* Auth */ 0, /* Addnl */ 0);
3278                 dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr, kGoodBye);
3279             }
3280         }
3281 
3282         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3283 
3284         sDnsMessages.Clear();
3285         AdvanceTime(15000);
3286         VerifyOrQuit(sDnsMessages.IsEmpty());
3287     }
3288 
3289     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
3290     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
3291 
3292     Log("End of test");
3293 
3294     testFreeInstance(sInstance);
3295 }
3296 
3297 //---------------------------------------------------------------------------------------------------------------------
3298 
TestQuery(void)3299 void TestQuery(void)
3300 {
3301     static const char *const kSubTypes[] = {"_s", "_r"};
3302 
3303     Core             *mdns = InitTest();
3304     Core::Host        host1;
3305     Core::Host        host2;
3306     Core::Service     service1;
3307     Core::Service     service2;
3308     Core::Service     service3;
3309     Core::Key         key1;
3310     Core::Key         key2;
3311     Ip6::Address      host1Addresses[3];
3312     Ip6::Address      host2Addresses[2];
3313     const DnsMessage *dnsMsg;
3314     uint16_t          heapAllocations;
3315     DnsNameString     host1FullName;
3316     DnsNameString     host2FullName;
3317     DnsNameString     service1FullName;
3318     DnsNameString     service2FullName;
3319     DnsNameString     service3FullName;
3320     KnownAnswer       knownAnswers[2];
3321 
3322     Log("-------------------------------------------------------------------------------------------");
3323     Log("TestQuery");
3324 
3325     AdvanceTime(1);
3326 
3327     heapAllocations = sHeapAllocatedPtrs.GetLength();
3328     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
3329 
3330     SuccessOrQuit(host1Addresses[0].FromString("fd00::1:aaaa"));
3331     SuccessOrQuit(host1Addresses[1].FromString("fd00::1:bbbb"));
3332     SuccessOrQuit(host1Addresses[2].FromString("fd00::1:cccc"));
3333     host1.mHostName        = "host1";
3334     host1.mAddresses       = host1Addresses;
3335     host1.mAddressesLength = 3;
3336     host1.mTtl             = 1500;
3337     host1FullName.Append("%s.local.", host1.mHostName);
3338 
3339     SuccessOrQuit(host2Addresses[0].FromString("fd00::2:eeee"));
3340     SuccessOrQuit(host2Addresses[1].FromString("fd00::2:ffff"));
3341     host2.mHostName        = "host2";
3342     host2.mAddresses       = host2Addresses;
3343     host2.mAddressesLength = 2;
3344     host2.mTtl             = 1500;
3345     host2FullName.Append("%s.local.", host2.mHostName);
3346 
3347     service1.mHostName            = host1.mHostName;
3348     service1.mServiceInstance     = "srv1";
3349     service1.mServiceType         = "_srv._udp";
3350     service1.mSubTypeLabels       = kSubTypes;
3351     service1.mSubTypeLabelsLength = 2;
3352     service1.mTxtData             = kTxtData1;
3353     service1.mTxtDataLength       = sizeof(kTxtData1);
3354     service1.mPort                = 1111;
3355     service1.mPriority            = 0;
3356     service1.mWeight              = 0;
3357     service1.mTtl                 = 1500;
3358     service1FullName.Append("%s.%s.local.", service1.mServiceInstance, service1.mServiceType);
3359 
3360     service2.mHostName            = host1.mHostName;
3361     service2.mServiceInstance     = "srv2";
3362     service2.mServiceType         = "_tst._tcp";
3363     service2.mSubTypeLabels       = nullptr;
3364     service2.mSubTypeLabelsLength = 0;
3365     service2.mTxtData             = nullptr;
3366     service2.mTxtDataLength       = 0;
3367     service2.mPort                = 2222;
3368     service2.mPriority            = 2;
3369     service2.mWeight              = 2;
3370     service2.mTtl                 = 1500;
3371     service2FullName.Append("%s.%s.local.", service2.mServiceInstance, service2.mServiceType);
3372 
3373     service3.mHostName            = host2.mHostName;
3374     service3.mServiceInstance     = "srv3";
3375     service3.mServiceType         = "_srv._udp";
3376     service3.mSubTypeLabels       = kSubTypes;
3377     service3.mSubTypeLabelsLength = 1;
3378     service3.mTxtData             = kTxtData2;
3379     service3.mTxtDataLength       = sizeof(kTxtData2);
3380     service3.mPort                = 3333;
3381     service3.mPriority            = 3;
3382     service3.mWeight              = 3;
3383     service3.mTtl                 = 1500;
3384     service3FullName.Append("%s.%s.local.", service3.mServiceInstance, service3.mServiceType);
3385 
3386     key1.mName          = host2.mHostName;
3387     key1.mServiceType   = nullptr;
3388     key1.mKeyData       = kKey1;
3389     key1.mKeyDataLength = sizeof(kKey1);
3390     key1.mTtl           = 8000;
3391 
3392     key2.mName          = service3.mServiceInstance;
3393     key2.mServiceType   = service3.mServiceType;
3394     key2.mKeyData       = kKey1;
3395     key2.mKeyDataLength = sizeof(kKey1);
3396     key2.mTtl           = 8000;
3397 
3398     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3399     Log("Register 2 hosts and 3 services and 2 keys");
3400 
3401     sDnsMessages.Clear();
3402 
3403     for (RegCallback &regCallbck : sRegCallbacks)
3404     {
3405         regCallbck.Reset();
3406     }
3407 
3408     SuccessOrQuit(mdns->RegisterHost(host1, 0, HandleSuccessCallback));
3409     SuccessOrQuit(mdns->RegisterHost(host2, 1, HandleSuccessCallback));
3410     SuccessOrQuit(mdns->RegisterService(service1, 2, HandleSuccessCallback));
3411     SuccessOrQuit(mdns->RegisterService(service2, 3, HandleSuccessCallback));
3412     SuccessOrQuit(mdns->RegisterService(service3, 4, HandleSuccessCallback));
3413     SuccessOrQuit(mdns->RegisterKey(key1, 5, HandleSuccessCallback));
3414     SuccessOrQuit(mdns->RegisterKey(key2, 6, HandleSuccessCallback));
3415 
3416     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3417     Log("Validate probes for all entries");
3418 
3419     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
3420     {
3421         sDnsMessages.Clear();
3422         AdvanceTime(250);
3423 
3424         VerifyOrQuit(!sDnsMessages.IsEmpty());
3425         dnsMsg = sDnsMessages.GetHead();
3426 
3427         for (uint16_t index = 0; index < 7; index++)
3428         {
3429             VerifyOrQuit(!sRegCallbacks[index].mWasCalled);
3430         }
3431 
3432         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 5, /* Ans */ 0, /* Auth */ 13, /* Addnl */ 0);
3433 
3434         dnsMsg->ValidateAsProbeFor(host1, /* aUnicastRequest */ (probeCount == 0));
3435         dnsMsg->ValidateAsProbeFor(host2, /* aUnicastRequest */ (probeCount == 0));
3436         dnsMsg->ValidateAsProbeFor(service1, /* aUnicastRequest */ (probeCount == 0));
3437         dnsMsg->ValidateAsProbeFor(service2, /* aUnicastRequest */ (probeCount == 0));
3438         dnsMsg->ValidateAsProbeFor(service3, /* aUnicastRequest */ (probeCount == 0));
3439         dnsMsg->ValidateAsProbeFor(key1, /* aUnicastRequest */ (probeCount == 0));
3440         dnsMsg->ValidateAsProbeFor(key2, /* aUnicastRequest */ (probeCount == 0));
3441 
3442         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3443     }
3444 
3445     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3446     Log("Validate announcements for all entries");
3447 
3448     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
3449     {
3450         sDnsMessages.Clear();
3451 
3452         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
3453 
3454         for (uint16_t index = 0; index < 7; index++)
3455         {
3456             VerifyOrQuit(sRegCallbacks[index].mWasCalled);
3457         }
3458 
3459         VerifyOrQuit(!sDnsMessages.IsEmpty());
3460         dnsMsg = sDnsMessages.GetHead();
3461 
3462         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 21, /* Auth */ 0, /* Addnl */ 5);
3463 
3464         dnsMsg->Validate(host1, kInAnswerSection);
3465         dnsMsg->Validate(host2, kInAnswerSection);
3466         dnsMsg->Validate(service1, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
3467         dnsMsg->Validate(service2, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
3468         dnsMsg->Validate(service2, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
3469         dnsMsg->Validate(key1, kInAnswerSection);
3470         dnsMsg->Validate(key2, kInAnswerSection);
3471 
3472         for (uint16_t index = 0; index < service1.mSubTypeLabelsLength; index++)
3473         {
3474             dnsMsg->ValidateSubType(service1.mSubTypeLabels[index], service1);
3475         }
3476 
3477         for (uint16_t index = 0; index < service3.mSubTypeLabelsLength; index++)
3478         {
3479             dnsMsg->ValidateSubType(service3.mSubTypeLabels[index], service3);
3480         }
3481 
3482         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3483     }
3484 
3485     sDnsMessages.Clear();
3486     AdvanceTime(15000);
3487     VerifyOrQuit(sDnsMessages.IsEmpty());
3488 
3489     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3490     Log("Send a PTR query (browse) for `_srv._udp` and validate two answers and additional data");
3491 
3492     AdvanceTime(2000);
3493     sDnsMessages.Clear();
3494 
3495     SendQuery("_srv._udp.local.", ResourceRecord::kTypePtr);
3496 
3497     AdvanceTime(200);
3498 
3499     dnsMsg = sDnsMessages.GetHead();
3500     VerifyOrQuit(dnsMsg != nullptr);
3501     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3502 
3503     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 9);
3504 
3505     dnsMsg->Validate(service1, kInAnswerSection, kCheckPtr);
3506     dnsMsg->Validate(service3, kInAnswerSection, kCheckPtr);
3507     dnsMsg->Validate(service1, kInAdditionalSection, kCheckSrv | kCheckTxt);
3508     dnsMsg->Validate(service3, kInAdditionalSection, kCheckSrv | kCheckTxt);
3509     dnsMsg->Validate(host1, kInAdditionalSection);
3510     dnsMsg->Validate(host2, kInAdditionalSection);
3511 
3512     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3513     Log("Resend the same query but request a unicast response, validate the response");
3514 
3515     sDnsMessages.Clear();
3516     SendQuery("_srv._udp.local.", ResourceRecord::kTypePtr, ResourceRecord::kClassInternet | kClassQueryUnicastFlag);
3517 
3518     AdvanceTime(200);
3519 
3520     dnsMsg = sDnsMessages.GetHead();
3521     VerifyOrQuit(dnsMsg != nullptr);
3522     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3523 
3524     dnsMsg->ValidateHeader(kUnicastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 9);
3525 
3526     dnsMsg->Validate(service1, kInAnswerSection, kCheckPtr);
3527     dnsMsg->Validate(service3, kInAnswerSection, kCheckPtr);
3528     dnsMsg->Validate(service1, kInAdditionalSection, kCheckSrv | kCheckTxt);
3529     dnsMsg->Validate(service3, kInAdditionalSection, kCheckSrv | kCheckTxt);
3530     dnsMsg->Validate(host1, kInAdditionalSection);
3531     dnsMsg->Validate(host2, kInAdditionalSection);
3532 
3533     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3534     Log("Resend the same multicast query and validate that response is not emitted (rate limit)");
3535 
3536     sDnsMessages.Clear();
3537     SendQuery("_srv._udp.local.", ResourceRecord::kTypePtr);
3538 
3539     AdvanceTime(1000);
3540     VerifyOrQuit(sDnsMessages.IsEmpty());
3541 
3542     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3543     Log("Wait for > 1 second and resend the query and validate that now a response is emitted");
3544 
3545     SendQuery("_srv._udp.local.", ResourceRecord::kTypePtr);
3546 
3547     AdvanceTime(200);
3548 
3549     dnsMsg = sDnsMessages.GetHead();
3550     VerifyOrQuit(dnsMsg != nullptr);
3551     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3552 
3553     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 9);
3554 
3555     dnsMsg->Validate(service1, kInAnswerSection, kCheckPtr);
3556     dnsMsg->Validate(service3, kInAnswerSection, kCheckPtr);
3557     dnsMsg->Validate(service1, kInAdditionalSection, kCheckSrv | kCheckTxt);
3558     dnsMsg->Validate(service3, kInAdditionalSection, kCheckSrv | kCheckTxt);
3559     dnsMsg->Validate(host1, kInAdditionalSection);
3560     dnsMsg->Validate(host2, kInAdditionalSection);
3561 
3562     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3563     Log("Browse for sub-type `_s._sub._srv._udp` and validate two answers");
3564 
3565     sDnsMessages.Clear();
3566     SendQuery("_s._sub._srv._udp.local.", ResourceRecord::kTypePtr);
3567 
3568     AdvanceTime(200);
3569 
3570     dnsMsg = sDnsMessages.GetHead();
3571     VerifyOrQuit(dnsMsg != nullptr);
3572     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3573 
3574     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 9);
3575 
3576     dnsMsg->ValidateSubType("_s", service1);
3577     dnsMsg->ValidateSubType("_s", service3);
3578     dnsMsg->Validate(service1, kInAdditionalSection, kCheckSrv | kCheckTxt);
3579     dnsMsg->Validate(service3, kInAdditionalSection, kCheckSrv | kCheckTxt);
3580     dnsMsg->Validate(host1, kInAdditionalSection);
3581     dnsMsg->Validate(host2, kInAdditionalSection);
3582 
3583     // Send same query again and make sure it is ignored (rate limit).
3584 
3585     sDnsMessages.Clear();
3586     SendQuery("_s._sub._srv._udp.local.", ResourceRecord::kTypePtr);
3587 
3588     AdvanceTime(1000);
3589     VerifyOrQuit(sDnsMessages.IsEmpty());
3590 
3591     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3592     Log("Validate that query with `ANY class` instead of `IN class` is responded");
3593 
3594     AdvanceTime(2000);
3595 
3596     sDnsMessages.Clear();
3597     SendQuery("_r._sub._srv._udp.local.", ResourceRecord::kTypePtr, ResourceRecord::kClassAny);
3598 
3599     AdvanceTime(200);
3600 
3601     dnsMsg = sDnsMessages.GetHead();
3602     VerifyOrQuit(dnsMsg != nullptr);
3603     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3604 
3605     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 5);
3606     dnsMsg->ValidateSubType("_r", service1);
3607     dnsMsg->Validate(service1, kInAdditionalSection, kCheckSrv | kCheckTxt);
3608     dnsMsg->Validate(host1, kInAdditionalSection);
3609 
3610     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3611     Log("Validate that query with other `class` is ignored");
3612 
3613     AdvanceTime(2000);
3614 
3615     sDnsMessages.Clear();
3616     SendQuery("_r._sub._srv._udp.local.", ResourceRecord::kTypePtr, ResourceRecord::kClassNone);
3617 
3618     AdvanceTime(2000);
3619     VerifyOrQuit(sDnsMessages.IsEmpty());
3620 
3621     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3622     Log("Validate that query for non-registered name is ignored");
3623 
3624     sDnsMessages.Clear();
3625     SendQuery("_u._sub._srv._udp.local.", ResourceRecord::kTypeAny);
3626     SendQuery("host3.local.", ResourceRecord::kTypeAny);
3627 
3628     AdvanceTime(2000);
3629     VerifyOrQuit(sDnsMessages.IsEmpty());
3630 
3631     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3632     Log("Query for SRV for `srv1._srv._udp` and validate answer and additional data");
3633 
3634     sDnsMessages.Clear();
3635 
3636     SendQuery("srv1._srv._udp.local.", ResourceRecord::kTypeSrv);
3637 
3638     AdvanceTime(200);
3639 
3640     dnsMsg = sDnsMessages.GetHead();
3641     VerifyOrQuit(dnsMsg != nullptr);
3642     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3643 
3644     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 4);
3645 
3646     dnsMsg->Validate(service1, kInAnswerSection, kCheckSrv);
3647     dnsMsg->Validate(host1, kInAdditionalSection);
3648 
3649     //--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
3650     // Query with multiple questions
3651 
3652     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3653     Log("Send a query with two questions (SRV for service1 and AAAA for host1). Validate response");
3654 
3655     AdvanceTime(2000);
3656 
3657     sDnsMessages.Clear();
3658     SendQueryForTwo("srv1._srv._udp.local.", ResourceRecord::kTypeSrv, "host1.local.", ResourceRecord::kTypeAaaa);
3659 
3660     AdvanceTime(200);
3661 
3662     dnsMsg = sDnsMessages.GetHead();
3663     VerifyOrQuit(dnsMsg != nullptr);
3664     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3665 
3666     // Since AAAA record are already present in Answer they should not be appended
3667     // in Additional anymore (for the SRV query).
3668 
3669     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 2);
3670 
3671     dnsMsg->Validate(service1, kInAnswerSection, kCheckSrv);
3672     dnsMsg->Validate(host1, kInAnswerSection);
3673 
3674     //--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
3675     // Known-answer suppression
3676 
3677     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3678     Log("Send a PTR query for `_srv._udp` and include `srv1` as known-answer and validate response");
3679 
3680     knownAnswers[0].mPtrAnswer = "srv1._srv._udp.local.";
3681     knownAnswers[0].mTtl       = 1500;
3682 
3683     AdvanceTime(1000);
3684 
3685     sDnsMessages.Clear();
3686     SendPtrQueryWithKnownAnswers("_srv._udp.local.", knownAnswers, 1);
3687 
3688     AdvanceTime(200);
3689 
3690     dnsMsg = sDnsMessages.GetHead();
3691     VerifyOrQuit(dnsMsg != nullptr);
3692     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3693 
3694     // Response should include `service3` only
3695 
3696     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 4);
3697     dnsMsg->Validate(service3, kInAnswerSection, kCheckPtr);
3698     dnsMsg->Validate(service3, kInAdditionalSection, kCheckSrv | kCheckTxt);
3699     dnsMsg->Validate(host2, kInAdditionalSection);
3700 
3701     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3702     Log("Send a PTR query again with both services as known-answer, validate no response is emitted");
3703 
3704     knownAnswers[1].mPtrAnswer = "srv3._srv._udp.local.";
3705     knownAnswers[1].mTtl       = 1500;
3706 
3707     AdvanceTime(1000);
3708 
3709     sDnsMessages.Clear();
3710     SendPtrQueryWithKnownAnswers("_srv._udp.local.", knownAnswers, 2);
3711 
3712     AdvanceTime(2000);
3713     VerifyOrQuit(sDnsMessages.IsEmpty());
3714 
3715     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3716     Log("Send a PTR query for `_srv._udp` and include `srv1` as known-answer and validate response");
3717 
3718     knownAnswers[0].mPtrAnswer = "srv1._srv._udp.local.";
3719     knownAnswers[0].mTtl       = 1500;
3720 
3721     AdvanceTime(1000);
3722 
3723     sDnsMessages.Clear();
3724     SendPtrQueryWithKnownAnswers("_srv._udp.local.", knownAnswers, 1);
3725 
3726     AdvanceTime(200);
3727 
3728     dnsMsg = sDnsMessages.GetHead();
3729     VerifyOrQuit(dnsMsg != nullptr);
3730     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3731 
3732     // Response should include `service3` only
3733 
3734     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 4);
3735     dnsMsg->Validate(service3, kInAnswerSection, kCheckPtr);
3736     dnsMsg->Validate(service3, kInAdditionalSection, kCheckSrv | kCheckTxt);
3737     dnsMsg->Validate(host2, kInAdditionalSection);
3738 
3739     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3740     Log("Change the TTL for known-answer to less than half of record TTL and validate response");
3741 
3742     knownAnswers[1].mTtl = 1500 / 2 - 1;
3743 
3744     AdvanceTime(1000);
3745 
3746     sDnsMessages.Clear();
3747     SendPtrQueryWithKnownAnswers("_srv._udp.local.", knownAnswers, 2);
3748 
3749     AdvanceTime(200);
3750 
3751     dnsMsg = sDnsMessages.GetHead();
3752     VerifyOrQuit(dnsMsg != nullptr);
3753     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3754 
3755     // Response should include `service3` only since anwer TTL
3756     // is less than half of registered TTL
3757 
3758     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 4);
3759     dnsMsg->Validate(service3, kInAnswerSection, kCheckPtr);
3760     dnsMsg->Validate(service3, kInAdditionalSection, kCheckSrv | kCheckTxt);
3761     dnsMsg->Validate(host2, kInAdditionalSection);
3762 
3763     //--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
3764     // Query during Goodbye announcements
3765 
3766     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3767     Log("Unregister `service1` and wait for its two announcements and validate them");
3768 
3769     sDnsMessages.Clear();
3770     SuccessOrQuit(mdns->UnregisterService(service1));
3771 
3772     for (uint8_t anncCount = 0; anncCount < kNumAnnounces - 1; anncCount++)
3773     {
3774         sDnsMessages.Clear();
3775 
3776         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
3777 
3778         dnsMsg = sDnsMessages.GetHead();
3779         VerifyOrQuit(dnsMsg != nullptr);
3780         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3781 
3782         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 5, /* Auth */ 0, /* Addnl */ 0);
3783         dnsMsg->Validate(service1, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr, kGoodBye);
3784 
3785         for (uint16_t index = 0; index < service1.mSubTypeLabelsLength; index++)
3786         {
3787             dnsMsg->ValidateSubType(service1.mSubTypeLabels[index], service1, kGoodBye);
3788         }
3789     }
3790 
3791     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3792     Log("Send a query for removed `service1` before its final announcement, validate no response");
3793 
3794     sDnsMessages.Clear();
3795 
3796     AdvanceTime(1100);
3797     SendQuery("srv1._srv._udp.local.", ResourceRecord::kTypeSrv);
3798 
3799     AdvanceTime(200);
3800 
3801     VerifyOrQuit(sDnsMessages.IsEmpty());
3802 
3803     // Wait for final announcement and validate it
3804 
3805     AdvanceTime(2000);
3806 
3807     dnsMsg = sDnsMessages.GetHead();
3808     VerifyOrQuit(dnsMsg != nullptr);
3809     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3810 
3811     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 5, /* Auth */ 0, /* Addnl */ 0);
3812     dnsMsg->Validate(service1, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr, kGoodBye);
3813 
3814     for (uint16_t index = 0; index < service1.mSubTypeLabelsLength; index++)
3815     {
3816         dnsMsg->ValidateSubType(service1.mSubTypeLabels[index], service1, kGoodBye);
3817     }
3818 
3819     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
3820     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
3821 
3822     Log("End of test");
3823 
3824     testFreeInstance(sInstance);
3825 }
3826 
3827 //----------------------------------------------------------------------------------------------------------------------
3828 
TestMultiPacket(void)3829 void TestMultiPacket(void)
3830 {
3831     static const char *const kSubTypes[] = {"_s1", "_r2", "vxy"};
3832 
3833     Core             *mdns = InitTest();
3834     Core::Service     service;
3835     const DnsMessage *dnsMsg;
3836     uint16_t          heapAllocations;
3837     DnsNameString     fullServiceName;
3838     DnsNameString     fullServiceType;
3839     KnownAnswer       knownAnswers[2];
3840 
3841     Log("-------------------------------------------------------------------------------------------");
3842     Log("TestMultiPacket");
3843 
3844     AdvanceTime(1);
3845 
3846     heapAllocations = sHeapAllocatedPtrs.GetLength();
3847     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
3848 
3849     service.mHostName            = "myhost";
3850     service.mServiceInstance     = "mysrv";
3851     service.mServiceType         = "_tst._udp";
3852     service.mSubTypeLabels       = kSubTypes;
3853     service.mSubTypeLabelsLength = 3;
3854     service.mTxtData             = kTxtData1;
3855     service.mTxtDataLength       = sizeof(kTxtData1);
3856     service.mPort                = 2222;
3857     service.mPriority            = 3;
3858     service.mWeight              = 4;
3859     service.mTtl                 = 2000;
3860 
3861     fullServiceName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
3862     fullServiceType.Append("%s.local.", service.mServiceType);
3863 
3864     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3865     Log("Register a `ServiceEntry` with sub-types, check probes and announcements");
3866 
3867     sDnsMessages.Clear();
3868 
3869     sRegCallbacks[0].Reset();
3870     SuccessOrQuit(mdns->RegisterService(service, 0, HandleSuccessCallback));
3871 
3872     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
3873     {
3874         sDnsMessages.Clear();
3875 
3876         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
3877         AdvanceTime(250);
3878 
3879         VerifyOrQuit(!sDnsMessages.IsEmpty());
3880         dnsMsg = sDnsMessages.GetHead();
3881         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
3882         dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ (probeCount == 0));
3883         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3884     }
3885 
3886     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
3887     {
3888         sDnsMessages.Clear();
3889 
3890         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
3891         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
3892 
3893         VerifyOrQuit(!sDnsMessages.IsEmpty());
3894         dnsMsg = sDnsMessages.GetHead();
3895         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 7, /* Auth */ 0, /* Addnl */ 1);
3896         dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
3897 
3898         for (uint16_t index = 0; index < service.mSubTypeLabelsLength; index++)
3899         {
3900             dnsMsg->ValidateSubType(service.mSubTypeLabels[index], service);
3901         }
3902 
3903         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
3904     }
3905 
3906     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3907     Log("Send a query for PTR record for service type and validate the response");
3908 
3909     AdvanceTime(2000);
3910 
3911     sDnsMessages.Clear();
3912     SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr);
3913 
3914     AdvanceTime(1000);
3915 
3916     dnsMsg = sDnsMessages.GetHead();
3917     VerifyOrQuit(dnsMsg != nullptr);
3918     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 2);
3919     dnsMsg->Validate(service, kInAnswerSection, kCheckPtr);
3920     dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
3921 
3922     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3923     Log("Send a PTR query again but mark it as truncated");
3924 
3925     AdvanceTime(2000);
3926 
3927     sDnsMessages.Clear();
3928     SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
3929               /* aTruncated */ true);
3930 
3931     Log("Since message is marked as `truncated`, mDNS should wait at least 400 msec");
3932 
3933     AdvanceTime(400);
3934     VerifyOrQuit(sDnsMessages.IsEmpty());
3935 
3936     AdvanceTime(2000);
3937     dnsMsg = sDnsMessages.GetHead();
3938     VerifyOrQuit(dnsMsg != nullptr);
3939     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 2);
3940     dnsMsg->Validate(service, kInAnswerSection, kCheckPtr);
3941     dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
3942 
3943     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3944     Log("Send a PTR query again as truncated followed-up by a non-matching answer");
3945 
3946     AdvanceTime(2000);
3947 
3948     sDnsMessages.Clear();
3949     SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
3950               /* aTruncated */ true);
3951     AdvanceTime(10);
3952 
3953     knownAnswers[0].mPtrAnswer = "other._tst._udp.local.";
3954     knownAnswers[0].mTtl       = 1500;
3955 
3956     SendEmtryPtrQueryWithKnownAnswers(fullServiceType.AsCString(), knownAnswers, 1);
3957 
3958     AdvanceTime(1000);
3959     dnsMsg = sDnsMessages.GetHead();
3960     VerifyOrQuit(dnsMsg != nullptr);
3961     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 2);
3962     dnsMsg->Validate(service, kInAnswerSection, kCheckPtr);
3963     dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
3964 
3965     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3966     Log("Send a PTR query again as truncated now followed-up by matching known-answer");
3967 
3968     AdvanceTime(2000);
3969 
3970     sDnsMessages.Clear();
3971     SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
3972               /* aTruncated */ true);
3973     AdvanceTime(10);
3974 
3975     knownAnswers[1].mPtrAnswer = "mysrv._tst._udp.local.";
3976     knownAnswers[1].mTtl       = 1500;
3977 
3978     SendEmtryPtrQueryWithKnownAnswers(fullServiceType.AsCString(), knownAnswers, 2);
3979 
3980     Log("We expect no response since the followed-up message contains a matching known-answer");
3981     AdvanceTime(5000);
3982     VerifyOrQuit(sDnsMessages.IsEmpty());
3983 
3984     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
3985     Log("Send a truncated query for PTR record for `services._dns-sd`");
3986 
3987     AdvanceTime(2000);
3988 
3989     sDnsMessages.Clear();
3990     SendQuery("_services._dns-sd._udp.local.", ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
3991               /* aTruncated */ true);
3992 
3993     Log("Response should be sent after longer wait time");
3994     AdvanceTime(1000);
3995 
3996     dnsMsg = sDnsMessages.GetHead();
3997     VerifyOrQuit(dnsMsg != nullptr);
3998     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
3999     dnsMsg->Validate(service, kInAnswerSection, kCheckServicesPtr);
4000 
4001     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4002     Log("Send a truncated query for PTR record for `services._dns-sd` folloed by known-aswer");
4003 
4004     AdvanceTime(2000);
4005 
4006     sDnsMessages.Clear();
4007     SendQuery("_services._dns-sd._udp.local.", ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
4008               /* aTruncated */ true);
4009 
4010     AdvanceTime(20);
4011     knownAnswers[0].mPtrAnswer = "_other._udp.local.";
4012     knownAnswers[0].mTtl       = 4500;
4013 
4014     SendEmtryPtrQueryWithKnownAnswers("_services._dns-sd._udp.local.", knownAnswers, 1);
4015 
4016     Log("Response should be sent again due to answer not matching");
4017     AdvanceTime(1000);
4018 
4019     dnsMsg = sDnsMessages.GetHead();
4020     VerifyOrQuit(dnsMsg != nullptr);
4021     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
4022     dnsMsg->Validate(service, kInAnswerSection, kCheckServicesPtr);
4023 
4024     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4025     Log("Send the same truncated query again but follow-up with a matching known-answer message");
4026 
4027     AdvanceTime(2000);
4028 
4029     sDnsMessages.Clear();
4030     SendQuery("_services._dns-sd._udp.local.", ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
4031               /* aTruncated */ true);
4032 
4033     AdvanceTime(20);
4034     knownAnswers[1].mPtrAnswer = "_tst._udp.local.";
4035     knownAnswers[1].mTtl       = 4500;
4036 
4037     SendEmtryPtrQueryWithKnownAnswers("_services._dns-sd._udp.local.", knownAnswers, 2);
4038 
4039     Log("We expect no response since the followed-up message contains a matching known-answer");
4040     AdvanceTime(5000);
4041     VerifyOrQuit(sDnsMessages.IsEmpty());
4042 
4043     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
4044     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
4045 
4046     Log("End of test");
4047 
4048     testFreeInstance(sInstance);
4049 }
4050 
TestResponseAggregation(void)4051 void TestResponseAggregation(void)
4052 {
4053     Core             *mdns = InitTest();
4054     Core::Service     tcpService;
4055     Core::Service     udpService;
4056     const DnsMessage *dnsMsg;
4057     uint16_t          heapAllocations;
4058     DnsNameString     fullTcpServiceName;
4059     DnsNameString     fullTcpServiceType;
4060     DnsNameString     fullUdpServiceName;
4061     DnsNameString     fullUdpServiceType;
4062 
4063     Log("-------------------------------------------------------------------------------------------");
4064     Log("TestResponseAggregation");
4065 
4066     AdvanceTime(1);
4067 
4068     heapAllocations = sHeapAllocatedPtrs.GetLength();
4069     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
4070 
4071     tcpService.mHostName            = "host";
4072     tcpService.mServiceInstance     = "srv1";
4073     tcpService.mServiceType         = "_matter._tcp";
4074     tcpService.mSubTypeLabels       = nullptr;
4075     tcpService.mSubTypeLabelsLength = 0;
4076     tcpService.mTxtData             = kTxtData1;
4077     tcpService.mTxtDataLength       = sizeof(kTxtData1);
4078     tcpService.mPort                = 1111;
4079     tcpService.mPriority            = 1;
4080     tcpService.mWeight              = 2;
4081     tcpService.mTtl                 = 4500;
4082 
4083     udpService.mHostName            = "host";
4084     udpService.mServiceInstance     = "srv2";
4085     udpService.mServiceType         = "_srv._udp";
4086     udpService.mSubTypeLabels       = nullptr;
4087     udpService.mSubTypeLabelsLength = 0;
4088     udpService.mTxtData             = kTxtData2;
4089     udpService.mTxtDataLength       = sizeof(kTxtData2);
4090     udpService.mPort                = 2222;
4091     udpService.mPriority            = 6;
4092     udpService.mWeight              = 2;
4093     udpService.mTtl                 = 4500;
4094 
4095     fullTcpServiceName.Append("%s.%s.local.", tcpService.mServiceInstance, tcpService.mServiceType);
4096     fullTcpServiceType.Append("%s.local.", tcpService.mServiceType);
4097 
4098     fullUdpServiceName.Append("%s.%s.local.", udpService.mServiceInstance, udpService.mServiceType);
4099     fullUdpServiceType.Append("%s.local.", udpService.mServiceType);
4100 
4101     Log("-------------------------------------------------------------------------------------------");
4102     Log("Register a first `ServiceEntry`, check probes and announcements");
4103 
4104     sDnsMessages.Clear();
4105 
4106     sRegCallbacks[0].Reset();
4107     SuccessOrQuit(mdns->RegisterService(tcpService, 0, HandleSuccessCallback));
4108 
4109     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
4110     {
4111         sDnsMessages.Clear();
4112 
4113         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4114         AdvanceTime(250);
4115 
4116         VerifyOrQuit(!sDnsMessages.IsEmpty());
4117         dnsMsg = sDnsMessages.GetHead();
4118         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
4119         dnsMsg->ValidateAsProbeFor(tcpService, /* aUnicastRequest */ (probeCount == 0));
4120         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4121     }
4122 
4123     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
4124     {
4125         sDnsMessages.Clear();
4126 
4127         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
4128         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4129 
4130         VerifyOrQuit(!sDnsMessages.IsEmpty());
4131         dnsMsg = sDnsMessages.GetHead();
4132         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
4133         dnsMsg->Validate(tcpService, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
4134 
4135         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4136     }
4137 
4138     Log("-------------------------------------------------------------------------------------------");
4139     Log("Register a second `ServiceEntry`, check probes and announcements");
4140 
4141     sDnsMessages.Clear();
4142 
4143     sRegCallbacks[0].Reset();
4144     SuccessOrQuit(mdns->RegisterService(udpService, 0, HandleSuccessCallback));
4145 
4146     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
4147     {
4148         sDnsMessages.Clear();
4149 
4150         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4151         AdvanceTime(250);
4152 
4153         VerifyOrQuit(!sDnsMessages.IsEmpty());
4154         dnsMsg = sDnsMessages.GetHead();
4155         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
4156         dnsMsg->ValidateAsProbeFor(udpService, /* aUnicastRequest */ (probeCount == 0));
4157         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4158     }
4159 
4160     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
4161     {
4162         sDnsMessages.Clear();
4163 
4164         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
4165         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4166 
4167         VerifyOrQuit(!sDnsMessages.IsEmpty());
4168         dnsMsg = sDnsMessages.GetHead();
4169         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
4170         dnsMsg->Validate(udpService, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
4171         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4172     }
4173 
4174     Log("-------------------------------------------------------------------------------------------");
4175     Log("Send two PTR queries back to back and validate the response is aggregated");
4176 
4177     AdvanceTime(2000);
4178 
4179     sDnsMessages.Clear();
4180     SendQuery(fullTcpServiceType.AsCString(), ResourceRecord::kTypePtr);
4181     AdvanceTime(5);
4182     SendQuery(fullUdpServiceType.AsCString(), ResourceRecord::kTypePtr);
4183 
4184     AdvanceTime(1000);
4185 
4186     dnsMsg = sDnsMessages.GetHead();
4187     VerifyOrQuit(dnsMsg != nullptr);
4188     dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 4);
4189     dnsMsg->Validate(tcpService, kInAnswerSection, kCheckPtr);
4190     dnsMsg->Validate(tcpService, kInAdditionalSection, kCheckSrv | kCheckTxt);
4191     dnsMsg->Validate(udpService, kInAnswerSection, kCheckPtr);
4192     dnsMsg->Validate(udpService, kInAdditionalSection, kCheckSrv | kCheckTxt);
4193     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4194 
4195     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
4196     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
4197 
4198     Log("End of test");
4199 
4200     testFreeInstance(sInstance);
4201 }
4202 
4203 //---------------------------------------------------------------------------------------------------------------------
4204 
TestQuestionUnicastDisallowed(void)4205 void TestQuestionUnicastDisallowed(void)
4206 {
4207     Core             *mdns = InitTest();
4208     Core::Host        host;
4209     Ip6::Address      hostAddresses[1];
4210     const DnsMessage *dnsMsg;
4211     uint16_t          heapAllocations;
4212     DnsNameString     hostFullName;
4213 
4214     Log("-------------------------------------------------------------------------------------------");
4215     Log("TestQuestionUnicastDisallowed");
4216 
4217     AdvanceTime(1);
4218 
4219     heapAllocations = sHeapAllocatedPtrs.GetLength();
4220     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
4221 
4222     SuccessOrQuit(hostAddresses[0].FromString("fd00::1234"));
4223 
4224     host.mHostName        = "myhost";
4225     host.mAddresses       = hostAddresses;
4226     host.mAddressesLength = 1;
4227     host.mTtl             = 1500;
4228 
4229     mdns->SetQuestionUnicastAllowed(false);
4230     VerifyOrQuit(!mdns->IsQuestionUnicastAllowed());
4231 
4232     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4233     Log("Register a `HostEntry`, check probes and announcements");
4234 
4235     sDnsMessages.Clear();
4236 
4237     sRegCallbacks[0].Reset();
4238     SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
4239 
4240     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
4241     {
4242         sDnsMessages.Clear();
4243 
4244         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4245         AdvanceTime(250);
4246 
4247         VerifyOrQuit(!sDnsMessages.IsEmpty());
4248         dnsMsg = sDnsMessages.GetHead();
4249         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 1, /* Addnl */ 0);
4250         dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ false);
4251         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4252     }
4253 
4254     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
4255     {
4256         sDnsMessages.Clear();
4257 
4258         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
4259         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4260 
4261         VerifyOrQuit(!sDnsMessages.IsEmpty());
4262         dnsMsg = sDnsMessages.GetHead();
4263         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
4264         dnsMsg->Validate(host, kInAnswerSection);
4265         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4266     }
4267 
4268     sDnsMessages.Clear();
4269     AdvanceTime(15000);
4270     VerifyOrQuit(sDnsMessages.IsEmpty());
4271 
4272     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
4273     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
4274 
4275     Log("End of test");
4276 
4277     testFreeInstance(sInstance);
4278 }
4279 
4280 //---------------------------------------------------------------------------------------------------------------------
4281 
TestTxMessageSizeLimit(void)4282 void TestTxMessageSizeLimit(void)
4283 {
4284     Core             *mdns = InitTest();
4285     Core::Host        host;
4286     Core::Service     service;
4287     Core::Key         hostKey;
4288     Core::Key         serviceKey;
4289     Ip6::Address      hostAddresses[3];
4290     uint8_t           keyData[300];
4291     const DnsMessage *dnsMsg;
4292     uint16_t          heapAllocations;
4293     DnsNameString     hostFullName;
4294     DnsNameString     serviceFullName;
4295 
4296     memset(keyData, 1, sizeof(keyData));
4297 
4298     Log("-------------------------------------------------------------------------------------------");
4299     Log("TestTxMessageSizeLimit");
4300 
4301     AdvanceTime(1);
4302 
4303     heapAllocations = sHeapAllocatedPtrs.GetLength();
4304     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
4305 
4306     SuccessOrQuit(hostAddresses[0].FromString("fd00::1:aaaa"));
4307     SuccessOrQuit(hostAddresses[1].FromString("fd00::1:bbbb"));
4308     SuccessOrQuit(hostAddresses[2].FromString("fd00::1:cccc"));
4309     host.mHostName        = "myhost";
4310     host.mAddresses       = hostAddresses;
4311     host.mAddressesLength = 3;
4312     host.mTtl             = 1500;
4313     hostFullName.Append("%s.local.", host.mHostName);
4314 
4315     service.mHostName            = host.mHostName;
4316     service.mServiceInstance     = "mysrv";
4317     service.mServiceType         = "_srv._udp";
4318     service.mSubTypeLabels       = nullptr;
4319     service.mSubTypeLabelsLength = 0;
4320     service.mTxtData             = kTxtData1;
4321     service.mTxtDataLength       = sizeof(kTxtData1);
4322     service.mPort                = 1111;
4323     service.mPriority            = 0;
4324     service.mWeight              = 0;
4325     service.mTtl                 = 1500;
4326     serviceFullName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
4327 
4328     hostKey.mName          = host.mHostName;
4329     hostKey.mServiceType   = nullptr;
4330     hostKey.mKeyData       = keyData;
4331     hostKey.mKeyDataLength = 300;
4332     hostKey.mTtl           = 8000;
4333 
4334     serviceKey.mName          = service.mServiceInstance;
4335     serviceKey.mServiceType   = service.mServiceType;
4336     serviceKey.mKeyData       = keyData;
4337     serviceKey.mKeyDataLength = 300;
4338     serviceKey.mTtl           = 8000;
4339 
4340     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4341     Log("Set `MaxMessageSize` to 340 and use large key record data to trigger size limit behavior");
4342 
4343     mdns->SetMaxMessageSize(340);
4344 
4345     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4346     Log("Register host and service and keys for each");
4347 
4348     sDnsMessages.Clear();
4349 
4350     for (RegCallback &regCallbck : sRegCallbacks)
4351     {
4352         regCallbck.Reset();
4353     }
4354 
4355     SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
4356     SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
4357     SuccessOrQuit(mdns->RegisterKey(hostKey, 2, HandleSuccessCallback));
4358     SuccessOrQuit(mdns->RegisterKey(serviceKey, 3, HandleSuccessCallback));
4359 
4360     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4361     Log("Validate probes for all entries");
4362     Log("Probes for host and service should be broken into separate message due to size limit");
4363 
4364     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
4365     {
4366         sDnsMessages.Clear();
4367         AdvanceTime(250);
4368 
4369         VerifyOrQuit(!sDnsMessages.IsEmpty());
4370         dnsMsg = sDnsMessages.GetHead();
4371 
4372         for (uint16_t index = 0; index < 4; index++)
4373         {
4374             VerifyOrQuit(!sRegCallbacks[index].mWasCalled);
4375         }
4376 
4377         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 4, /* Addnl */ 0);
4378         dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ (probeCount == 0));
4379         dnsMsg->ValidateAsProbeFor(hostKey, /* aUnicastRequest */ (probeCount == 0));
4380 
4381         dnsMsg = dnsMsg->GetNext();
4382         VerifyOrQuit(dnsMsg != nullptr);
4383 
4384         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 3, /* Addnl */ 0);
4385         dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ (probeCount == 0));
4386         dnsMsg->ValidateAsProbeFor(serviceKey, /* aUnicastRequest */ (probeCount == 0));
4387 
4388         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4389     }
4390 
4391     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4392     Log("Validate announcements for all entries");
4393     Log("Announces should also be broken into separate message due to size limit");
4394 
4395     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
4396     {
4397         sDnsMessages.Clear();
4398 
4399         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
4400 
4401         for (uint16_t index = 0; index < 4; index++)
4402         {
4403             VerifyOrQuit(sRegCallbacks[index].mWasCalled);
4404         }
4405 
4406         VerifyOrQuit(!sDnsMessages.IsEmpty());
4407         dnsMsg = sDnsMessages.GetHead();
4408 
4409         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
4410         dnsMsg->Validate(host, kInAnswerSection);
4411         dnsMsg->Validate(hostKey, kInAnswerSection);
4412 
4413         dnsMsg = dnsMsg->GetNext();
4414         VerifyOrQuit(dnsMsg != nullptr);
4415 
4416         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 4);
4417         dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr);
4418         dnsMsg->Validate(serviceKey, kInAnswerSection);
4419 
4420         dnsMsg = dnsMsg->GetNext();
4421         VerifyOrQuit(dnsMsg != nullptr);
4422 
4423         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
4424         dnsMsg->Validate(service, kInAnswerSection, kCheckServicesPtr);
4425 
4426         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4427     }
4428 
4429     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
4430     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
4431 
4432     Log("End of test");
4433 
4434     testFreeInstance(sInstance);
4435 }
4436 
4437 //---------------------------------------------------------------------------------------------------------------------
4438 
TestHostConflict(void)4439 void TestHostConflict(void)
4440 {
4441     Core             *mdns = InitTest();
4442     Core::Host        host;
4443     Ip6::Address      hostAddresses[2];
4444     const DnsMessage *dnsMsg;
4445     uint16_t          heapAllocations;
4446     DnsNameString     hostFullName;
4447 
4448     Log("-------------------------------------------------------------------------------------------");
4449     Log("TestHostConflict");
4450 
4451     AdvanceTime(1);
4452 
4453     heapAllocations = sHeapAllocatedPtrs.GetLength();
4454     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
4455 
4456     SuccessOrQuit(hostAddresses[0].FromString("fd00::1"));
4457     SuccessOrQuit(hostAddresses[1].FromString("fd00::2"));
4458 
4459     host.mHostName        = "myhost";
4460     host.mAddresses       = hostAddresses;
4461     host.mAddressesLength = 2;
4462     host.mTtl             = 1500;
4463 
4464     hostFullName.Append("%s.local.", host.mHostName);
4465 
4466     // Run the test twice, first run send response with record in Answer section,
4467     // section run in Additional Data section.
4468 
4469     sConflictCallback.Reset();
4470     mdns->SetConflictCallback(HandleConflict);
4471 
4472     for (uint8_t iter = 0; iter < 2; iter++)
4473     {
4474         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4475         Log("Register a `HostEntry`, wait for first probe");
4476 
4477         sDnsMessages.Clear();
4478 
4479         sRegCallbacks[0].Reset();
4480         SuccessOrQuit(mdns->RegisterHost(host, 0, HandleCallback));
4481 
4482         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4483         AdvanceTime(250);
4484 
4485         VerifyOrQuit(!sDnsMessages.IsEmpty());
4486         dnsMsg = sDnsMessages.GetHead();
4487         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
4488         dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ true);
4489         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4490 
4491         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4492         Log("Send a response claiming the name with record in %s section", (iter == 0) ? "answer" : "additional");
4493 
4494         SendResponseWithEmptyKey(hostFullName.AsCString(), (iter == 0) ? kInAnswerSection : kInAdditionalSection);
4495         AdvanceTime(1);
4496 
4497         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4498         VerifyOrQuit(sRegCallbacks[0].mError == kErrorDuplicated);
4499 
4500         VerifyOrQuit(!sConflictCallback.mWasCalled);
4501 
4502         sDnsMessages.Clear();
4503 
4504         SuccessOrQuit(mdns->UnregisterHost(host));
4505 
4506         AdvanceTime(15000);
4507         VerifyOrQuit(sDnsMessages.IsEmpty());
4508     }
4509 
4510     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4511     Log("Register a `HostEntry` and respond to probe to trigger conflict");
4512 
4513     sRegCallbacks[0].Reset();
4514     SuccessOrQuit(mdns->RegisterHost(host, 0, HandleCallback));
4515 
4516     VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4517 
4518     SendResponseWithEmptyKey(hostFullName.AsCString(), kInAnswerSection);
4519     AdvanceTime(1);
4520 
4521     VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4522     VerifyOrQuit(sRegCallbacks[0].mError == kErrorDuplicated);
4523     VerifyOrQuit(!sConflictCallback.mWasCalled);
4524 
4525     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4526     Log("Register the conflicted `HostEntry` again, and make sure no probes are sent");
4527 
4528     sRegCallbacks[1].Reset();
4529     sConflictCallback.Reset();
4530     sDnsMessages.Clear();
4531 
4532     SuccessOrQuit(mdns->RegisterHost(host, 1, HandleCallback));
4533     AdvanceTime(5000);
4534 
4535     VerifyOrQuit(sRegCallbacks[1].mWasCalled);
4536     VerifyOrQuit(sRegCallbacks[1].mError == kErrorDuplicated);
4537     VerifyOrQuit(!sConflictCallback.mWasCalled);
4538 
4539     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4540     Log("Unregister the conflicted host and register it again immediately, make sure we see probes");
4541 
4542     SuccessOrQuit(mdns->UnregisterHost(host));
4543 
4544     sConflictCallback.Reset();
4545     sRegCallbacks[0].Reset();
4546     SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
4547 
4548     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
4549     {
4550         sDnsMessages.Clear();
4551 
4552         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4553         AdvanceTime(250);
4554 
4555         VerifyOrQuit(!sDnsMessages.IsEmpty());
4556         dnsMsg = sDnsMessages.GetHead();
4557         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
4558         dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ (probeCount == 0));
4559         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4560     }
4561 
4562     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
4563     {
4564         sDnsMessages.Clear();
4565 
4566         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
4567         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4568 
4569         VerifyOrQuit(!sDnsMessages.IsEmpty());
4570         dnsMsg = sDnsMessages.GetHead();
4571         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
4572         dnsMsg->Validate(host, kInAnswerSection);
4573         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4574     }
4575 
4576     VerifyOrQuit(!sConflictCallback.mWasCalled);
4577 
4578     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4579     Log("Send a response for host name and validate that conflict is detected and callback is called");
4580 
4581     SendResponseWithEmptyKey(hostFullName.AsCString(), kInAnswerSection);
4582     AdvanceTime(1);
4583 
4584     VerifyOrQuit(sConflictCallback.mWasCalled);
4585     VerifyOrQuit(StringMatch(sConflictCallback.mName.AsCString(), host.mHostName, kStringCaseInsensitiveMatch));
4586     VerifyOrQuit(!sConflictCallback.mHasServiceType);
4587 
4588     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
4589     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
4590 
4591     Log("End of test");
4592 
4593     testFreeInstance(sInstance);
4594 }
4595 
4596 //---------------------------------------------------------------------------------------------------------------------
4597 
TestServiceConflict(void)4598 void TestServiceConflict(void)
4599 {
4600     Core             *mdns = InitTest();
4601     Core::Service     service;
4602     const DnsMessage *dnsMsg;
4603     uint16_t          heapAllocations;
4604     DnsNameString     fullServiceName;
4605 
4606     Log("-------------------------------------------------------------------------------------------");
4607     Log("TestServiceConflict");
4608 
4609     service.mHostName            = "myhost";
4610     service.mServiceInstance     = "myservice";
4611     service.mServiceType         = "_srv._udp";
4612     service.mSubTypeLabels       = nullptr;
4613     service.mSubTypeLabelsLength = 0;
4614     service.mTxtData             = kTxtData1;
4615     service.mTxtDataLength       = sizeof(kTxtData1);
4616     service.mPort                = 1234;
4617     service.mPriority            = 1;
4618     service.mWeight              = 2;
4619     service.mTtl                 = 1000;
4620 
4621     fullServiceName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
4622 
4623     AdvanceTime(1);
4624 
4625     heapAllocations = sHeapAllocatedPtrs.GetLength();
4626     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
4627 
4628     // Run the test twice, first run send response with record in Answer section,
4629     // section run in Additional Data section.
4630 
4631     sConflictCallback.Reset();
4632     mdns->SetConflictCallback(HandleConflict);
4633 
4634     for (uint8_t iter = 0; iter < 2; iter++)
4635     {
4636         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4637         Log("Register a `ServiceEntry`, wait for first probe");
4638 
4639         sDnsMessages.Clear();
4640 
4641         sRegCallbacks[0].Reset();
4642         SuccessOrQuit(mdns->RegisterService(service, 0, HandleCallback));
4643 
4644         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4645         AdvanceTime(250);
4646 
4647         VerifyOrQuit(!sDnsMessages.IsEmpty());
4648         dnsMsg = sDnsMessages.GetHead();
4649         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
4650         dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ true);
4651         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4652 
4653         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4654         Log("Send a response claiming the name with record in %s section", (iter == 0) ? "answer" : "additional");
4655 
4656         SendResponseWithEmptyKey(fullServiceName.AsCString(), (iter == 0) ? kInAnswerSection : kInAdditionalSection);
4657         AdvanceTime(1);
4658 
4659         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4660         VerifyOrQuit(sRegCallbacks[0].mError == kErrorDuplicated);
4661 
4662         VerifyOrQuit(!sConflictCallback.mWasCalled);
4663 
4664         sDnsMessages.Clear();
4665 
4666         SuccessOrQuit(mdns->UnregisterService(service));
4667 
4668         AdvanceTime(15000);
4669         VerifyOrQuit(sDnsMessages.IsEmpty());
4670     }
4671 
4672     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4673     Log("Register a `ServiceEntry` and respond to probe to trigger conflict");
4674 
4675     sRegCallbacks[0].Reset();
4676     SuccessOrQuit(mdns->RegisterService(service, 0, HandleCallback));
4677 
4678     VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4679 
4680     SendResponseWithEmptyKey(fullServiceName.AsCString(), kInAnswerSection);
4681     AdvanceTime(1);
4682 
4683     VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4684     VerifyOrQuit(sRegCallbacks[0].mError == kErrorDuplicated);
4685     VerifyOrQuit(!sConflictCallback.mWasCalled);
4686 
4687     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4688     Log("Register the conflicted `ServiceEntry` again, and make sure no probes are sent");
4689 
4690     sRegCallbacks[1].Reset();
4691     sConflictCallback.Reset();
4692     sDnsMessages.Clear();
4693 
4694     SuccessOrQuit(mdns->RegisterService(service, 1, HandleCallback));
4695     AdvanceTime(5000);
4696 
4697     VerifyOrQuit(sRegCallbacks[1].mWasCalled);
4698     VerifyOrQuit(sRegCallbacks[1].mError == kErrorDuplicated);
4699     VerifyOrQuit(!sConflictCallback.mWasCalled);
4700 
4701     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4702     Log("Unregister the conflicted host and register it again immediately, make sure we see probes");
4703 
4704     SuccessOrQuit(mdns->UnregisterService(service));
4705 
4706     sConflictCallback.Reset();
4707     sRegCallbacks[0].Reset();
4708     SuccessOrQuit(mdns->RegisterService(service, 0, HandleSuccessCallback));
4709 
4710     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
4711     {
4712         sDnsMessages.Clear();
4713 
4714         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4715         AdvanceTime(250);
4716 
4717         VerifyOrQuit(!sDnsMessages.IsEmpty());
4718         dnsMsg = sDnsMessages.GetHead();
4719         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
4720         dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ (probeCount == 0));
4721         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4722     }
4723 
4724     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
4725     {
4726         sDnsMessages.Clear();
4727 
4728         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
4729         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4730 
4731         VerifyOrQuit(!sDnsMessages.IsEmpty());
4732         dnsMsg = sDnsMessages.GetHead();
4733         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
4734         dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
4735         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4736     }
4737 
4738     VerifyOrQuit(!sConflictCallback.mWasCalled);
4739 
4740     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4741     Log("Send a response for service name and validate that conflict is detected and callback is called");
4742 
4743     SendResponseWithEmptyKey(fullServiceName.AsCString(), kInAnswerSection);
4744     AdvanceTime(1);
4745 
4746     VerifyOrQuit(sConflictCallback.mWasCalled);
4747     VerifyOrQuit(
4748         StringMatch(sConflictCallback.mName.AsCString(), service.mServiceInstance, kStringCaseInsensitiveMatch));
4749     VerifyOrQuit(sConflictCallback.mHasServiceType);
4750     VerifyOrQuit(
4751         StringMatch(sConflictCallback.mServiceType.AsCString(), service.mServiceType, kStringCaseInsensitiveMatch));
4752 
4753     sDnsMessages.Clear();
4754     AdvanceTime(20000);
4755     VerifyOrQuit(sDnsMessages.IsEmpty());
4756 
4757     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
4758     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
4759 
4760     Log("End of test");
4761 
4762     testFreeInstance(sInstance);
4763 }
4764 
4765 //=====================================================================================================================
4766 // Browser/Resolver tests
4767 
4768 struct BrowseCallback : public Allocatable<BrowseCallback>, public LinkedListEntry<BrowseCallback>
4769 {
4770     BrowseCallback *mNext;
4771     DnsName         mServiceType;
4772     DnsName         mSubTypeLabel;
4773     DnsName         mServiceInstance;
4774     uint32_t        mTtl;
4775     bool            mIsSubType;
4776 };
4777 
4778 struct SrvCallback : public Allocatable<SrvCallback>, public LinkedListEntry<SrvCallback>
4779 {
4780     SrvCallback *mNext;
4781     DnsName      mServiceInstance;
4782     DnsName      mServiceType;
4783     DnsName      mHostName;
4784     uint16_t     mPort;
4785     uint16_t     mPriority;
4786     uint16_t     mWeight;
4787     uint32_t     mTtl;
4788 };
4789 
4790 struct TxtCallback : public Allocatable<TxtCallback>, public LinkedListEntry<TxtCallback>
4791 {
4792     static constexpr uint16_t kMaxTxtDataLength = 100;
4793 
Matchesot::Dns::Multicast::TxtCallback4794     template <uint16_t kSize> bool Matches(const uint8_t (&aData)[kSize]) const
4795     {
4796         return (mTxtDataLength == kSize) && (memcmp(mTxtData, aData, kSize) == 0);
4797     }
4798 
4799     TxtCallback *mNext;
4800     DnsName      mServiceInstance;
4801     DnsName      mServiceType;
4802     uint8_t      mTxtData[kMaxTxtDataLength];
4803     uint16_t     mTxtDataLength;
4804     uint32_t     mTtl;
4805 };
4806 
4807 struct AddrCallback : public Allocatable<AddrCallback>, public LinkedListEntry<AddrCallback>
4808 {
4809     static constexpr uint16_t kMaxNumAddrs = 16;
4810 
Containsot::Dns::Multicast::AddrCallback4811     bool Contains(const AddrAndTtl &aAddrAndTtl) const
4812     {
4813         bool contains = false;
4814 
4815         for (uint16_t index = 0; index < mNumAddrs; index++)
4816         {
4817             if (mAddrAndTtls[index] == aAddrAndTtl)
4818             {
4819                 contains = true;
4820                 break;
4821             }
4822         }
4823 
4824         return contains;
4825     }
4826 
Matchesot::Dns::Multicast::AddrCallback4827     bool Matches(const AddrAndTtl *aAddrAndTtls, uint16_t aNumAddrs) const
4828     {
4829         bool matches = true;
4830 
4831         VerifyOrExit(aNumAddrs == mNumAddrs, matches = false);
4832 
4833         for (uint16_t index = 0; index < mNumAddrs; index++)
4834         {
4835             if (!Contains(aAddrAndTtls[index]))
4836             {
4837                 ExitNow(matches = false);
4838             }
4839         }
4840 
4841     exit:
4842         return matches;
4843     }
4844 
4845     AddrCallback *mNext;
4846     DnsName       mHostName;
4847     AddrAndTtl    mAddrAndTtls[kMaxNumAddrs];
4848     uint16_t      mNumAddrs;
4849 };
4850 
4851 OwningList<BrowseCallback> sBrowseCallbacks;
4852 OwningList<SrvCallback>    sSrvCallbacks;
4853 OwningList<TxtCallback>    sTxtCallbacks;
4854 OwningList<AddrCallback>   sAddrCallbacks;
4855 
HandleBrowseResult(otInstance * aInstance,const otMdnsBrowseResult * aResult)4856 void HandleBrowseResult(otInstance *aInstance, const otMdnsBrowseResult *aResult)
4857 {
4858     BrowseCallback *entry;
4859 
4860     VerifyOrQuit(aInstance == sInstance);
4861     VerifyOrQuit(aResult != nullptr);
4862     VerifyOrQuit(aResult->mServiceType != nullptr);
4863     VerifyOrQuit(aResult->mServiceInstance != nullptr);
4864     VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
4865 
4866     Log("Browse callback: %s (subtype:%s) -> %s ttl:%lu", aResult->mServiceType,
4867         aResult->mSubTypeLabel == nullptr ? "(null)" : aResult->mSubTypeLabel, aResult->mServiceInstance,
4868         ToUlong(aResult->mTtl));
4869 
4870     entry = BrowseCallback::Allocate();
4871     VerifyOrQuit(entry != nullptr);
4872 
4873     entry->mServiceType.CopyFrom(aResult->mServiceType);
4874     entry->mSubTypeLabel.CopyFrom(aResult->mSubTypeLabel);
4875     entry->mServiceInstance.CopyFrom(aResult->mServiceInstance);
4876     entry->mTtl       = aResult->mTtl;
4877     entry->mIsSubType = (aResult->mSubTypeLabel != nullptr);
4878 
4879     sBrowseCallbacks.PushAfterTail(*entry);
4880 }
4881 
HandleBrowseResultAlternate(otInstance * aInstance,const otMdnsBrowseResult * aResult)4882 void HandleBrowseResultAlternate(otInstance *aInstance, const otMdnsBrowseResult *aResult)
4883 {
4884     Log("Alternate browse callback is called");
4885     HandleBrowseResult(aInstance, aResult);
4886 }
4887 
HandleSrvResult(otInstance * aInstance,const otMdnsSrvResult * aResult)4888 void HandleSrvResult(otInstance *aInstance, const otMdnsSrvResult *aResult)
4889 {
4890     SrvCallback *entry;
4891 
4892     VerifyOrQuit(aInstance == sInstance);
4893     VerifyOrQuit(aResult != nullptr);
4894     VerifyOrQuit(aResult->mServiceInstance != nullptr);
4895     VerifyOrQuit(aResult->mServiceType != nullptr);
4896     VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
4897 
4898     if (aResult->mTtl != 0)
4899     {
4900         VerifyOrQuit(aResult->mHostName != nullptr);
4901 
4902         Log("SRV callback: %s %s, host:%s port:%u, prio:%u, weight:%u, ttl:%lu", aResult->mServiceInstance,
4903             aResult->mServiceType, aResult->mHostName, aResult->mPort, aResult->mPriority, aResult->mWeight,
4904             ToUlong(aResult->mTtl));
4905     }
4906     else
4907     {
4908         Log("SRV callback: %s %s, ttl:%lu", aResult->mServiceInstance, aResult->mServiceType, ToUlong(aResult->mTtl));
4909     }
4910 
4911     entry = SrvCallback::Allocate();
4912     VerifyOrQuit(entry != nullptr);
4913 
4914     entry->mServiceInstance.CopyFrom(aResult->mServiceInstance);
4915     entry->mServiceType.CopyFrom(aResult->mServiceType);
4916     entry->mHostName.CopyFrom(aResult->mHostName);
4917     entry->mPort     = aResult->mPort;
4918     entry->mPriority = aResult->mPriority;
4919     entry->mWeight   = aResult->mWeight;
4920     entry->mTtl      = aResult->mTtl;
4921 
4922     sSrvCallbacks.PushAfterTail(*entry);
4923 }
4924 
HandleSrvResultAlternate(otInstance * aInstance,const otMdnsSrvResult * aResult)4925 void HandleSrvResultAlternate(otInstance *aInstance, const otMdnsSrvResult *aResult)
4926 {
4927     Log("Alternate SRV callback is called");
4928     HandleSrvResult(aInstance, aResult);
4929 }
4930 
HandleTxtResult(otInstance * aInstance,const otMdnsTxtResult * aResult)4931 void HandleTxtResult(otInstance *aInstance, const otMdnsTxtResult *aResult)
4932 {
4933     TxtCallback *entry;
4934 
4935     VerifyOrQuit(aInstance == sInstance);
4936     VerifyOrQuit(aResult != nullptr);
4937     VerifyOrQuit(aResult->mServiceInstance != nullptr);
4938     VerifyOrQuit(aResult->mServiceType != nullptr);
4939     VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
4940 
4941     VerifyOrQuit(aResult->mTxtDataLength <= TxtCallback::kMaxTxtDataLength);
4942 
4943     if (aResult->mTtl != 0)
4944     {
4945         VerifyOrQuit(aResult->mTxtData != nullptr);
4946 
4947         Log("TXT callback: %s %s, len:%u, ttl:%lu", aResult->mServiceInstance, aResult->mServiceType,
4948             aResult->mTxtDataLength, ToUlong(aResult->mTtl));
4949     }
4950     else
4951     {
4952         Log("TXT callback: %s %s, ttl:%lu", aResult->mServiceInstance, aResult->mServiceType, ToUlong(aResult->mTtl));
4953     }
4954 
4955     entry = TxtCallback::Allocate();
4956     VerifyOrQuit(entry != nullptr);
4957 
4958     entry->mServiceInstance.CopyFrom(aResult->mServiceInstance);
4959     entry->mServiceType.CopyFrom(aResult->mServiceType);
4960     entry->mTxtDataLength = aResult->mTxtDataLength;
4961     memcpy(entry->mTxtData, aResult->mTxtData, aResult->mTxtDataLength);
4962     entry->mTtl = aResult->mTtl;
4963 
4964     sTxtCallbacks.PushAfterTail(*entry);
4965 }
4966 
HandleTxtResultAlternate(otInstance * aInstance,const otMdnsTxtResult * aResult)4967 void HandleTxtResultAlternate(otInstance *aInstance, const otMdnsTxtResult *aResult)
4968 {
4969     Log("Alternate TXT callback is called");
4970     HandleTxtResult(aInstance, aResult);
4971 }
4972 
HandleAddrResult(otInstance * aInstance,const otMdnsAddressResult * aResult)4973 void HandleAddrResult(otInstance *aInstance, const otMdnsAddressResult *aResult)
4974 {
4975     AddrCallback *entry;
4976 
4977     VerifyOrQuit(aInstance == sInstance);
4978     VerifyOrQuit(aResult != nullptr);
4979     VerifyOrQuit(aResult->mHostName != nullptr);
4980     VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
4981 
4982     VerifyOrQuit(aResult->mAddressesLength <= AddrCallback::kMaxNumAddrs);
4983 
4984     entry = AddrCallback::Allocate();
4985     VerifyOrQuit(entry != nullptr);
4986 
4987     entry->mHostName.CopyFrom(aResult->mHostName);
4988     entry->mNumAddrs = aResult->mAddressesLength;
4989 
4990     Log("Addr callback: %s, num:%u", aResult->mHostName, aResult->mAddressesLength);
4991 
4992     for (uint16_t index = 0; index < aResult->mAddressesLength; index++)
4993     {
4994         entry->mAddrAndTtls[index].mAddress = AsCoreType(&aResult->mAddresses[index].mAddress);
4995         entry->mAddrAndTtls[index].mTtl     = aResult->mAddresses[index].mTtl;
4996 
4997         Log(" - %s, ttl:%lu", entry->mAddrAndTtls[index].mAddress.ToString().AsCString(),
4998             ToUlong(entry->mAddrAndTtls[index].mTtl));
4999     }
5000 
5001     sAddrCallbacks.PushAfterTail(*entry);
5002 }
5003 
HandleAddrResultAlternate(otInstance * aInstance,const otMdnsAddressResult * aResult)5004 void HandleAddrResultAlternate(otInstance *aInstance, const otMdnsAddressResult *aResult)
5005 {
5006     Log("Alternate addr callback is called");
5007     HandleAddrResult(aInstance, aResult);
5008 }
5009 
5010 //---------------------------------------------------------------------------------------------------------------------
5011 
TestBrowser(void)5012 void TestBrowser(void)
5013 {
5014     Core                 *mdns = InitTest();
5015     Core::Browser         browser;
5016     Core::Browser         browser2;
5017     const DnsMessage     *dnsMsg;
5018     const BrowseCallback *browseCallback;
5019     uint16_t              heapAllocations;
5020 
5021     Log("-------------------------------------------------------------------------------------------");
5022     Log("TestBrowser");
5023 
5024     AdvanceTime(1);
5025 
5026     heapAllocations = sHeapAllocatedPtrs.GetLength();
5027     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
5028 
5029     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5030     Log("Start a browser. Validate initial queries.");
5031 
5032     ClearAllBytes(browser);
5033 
5034     browser.mServiceType  = "_srv._udp";
5035     browser.mSubTypeLabel = nullptr;
5036     browser.mInfraIfIndex = kInfraIfIndex;
5037     browser.mCallback     = HandleBrowseResult;
5038 
5039     sDnsMessages.Clear();
5040     SuccessOrQuit(mdns->StartBrowser(browser));
5041 
5042     for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; queryCount++)
5043     {
5044         sDnsMessages.Clear();
5045 
5046         AdvanceTime((queryCount == 0) ? 125 : (1U << (queryCount - 1)) * 1000);
5047 
5048         VerifyOrQuit(!sDnsMessages.IsEmpty());
5049         dnsMsg = sDnsMessages.GetHead();
5050         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5051         dnsMsg->ValidateAsQueryFor(browser);
5052         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5053     }
5054 
5055     sDnsMessages.Clear();
5056 
5057     AdvanceTime(20000);
5058     VerifyOrQuit(sDnsMessages.IsEmpty());
5059 
5060     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5061     Log("Send a response. Validate callback result.");
5062 
5063     sBrowseCallbacks.Clear();
5064 
5065     SendPtrResponse("_srv._udp.local.", "mysrv._srv._udp.local.", 120, kInAnswerSection);
5066 
5067     AdvanceTime(1);
5068 
5069     VerifyOrQuit(!sBrowseCallbacks.IsEmpty());
5070     browseCallback = sBrowseCallbacks.GetHead();
5071     VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
5072     VerifyOrQuit(!browseCallback->mIsSubType);
5073     VerifyOrQuit(browseCallback->mServiceInstance.Matches("mysrv"));
5074     VerifyOrQuit(browseCallback->mTtl == 120);
5075     VerifyOrQuit(browseCallback->GetNext() == nullptr);
5076 
5077     VerifyOrQuit(sDnsMessages.IsEmpty());
5078 
5079     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5080     Log("Send another response. Validate callback result.");
5081 
5082     AdvanceTime(10000);
5083 
5084     sBrowseCallbacks.Clear();
5085 
5086     SendPtrResponse("_srv._udp.local.", "awesome._srv._udp.local.", 500, kInAnswerSection);
5087 
5088     AdvanceTime(1);
5089 
5090     VerifyOrQuit(!sBrowseCallbacks.IsEmpty());
5091     browseCallback = sBrowseCallbacks.GetHead();
5092     VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
5093     VerifyOrQuit(!browseCallback->mIsSubType);
5094     VerifyOrQuit(browseCallback->mServiceInstance.Matches("awesome"));
5095     VerifyOrQuit(browseCallback->mTtl == 500);
5096     VerifyOrQuit(browseCallback->GetNext() == nullptr);
5097 
5098     VerifyOrQuit(sDnsMessages.IsEmpty());
5099 
5100     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5101     Log("Start another browser for the same service and different callback. Validate results.");
5102 
5103     AdvanceTime(5000);
5104 
5105     browser2.mServiceType  = "_srv._udp";
5106     browser2.mSubTypeLabel = nullptr;
5107     browser2.mInfraIfIndex = kInfraIfIndex;
5108     browser2.mCallback     = HandleBrowseResultAlternate;
5109 
5110     sBrowseCallbacks.Clear();
5111 
5112     SuccessOrQuit(mdns->StartBrowser(browser2));
5113 
5114     browseCallback = sBrowseCallbacks.GetHead();
5115 
5116     for (uint8_t iter = 0; iter < 2; iter++)
5117     {
5118         VerifyOrQuit(browseCallback != nullptr);
5119 
5120         VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
5121         VerifyOrQuit(!browseCallback->mIsSubType);
5122 
5123         if (browseCallback->mServiceInstance.Matches("awesome"))
5124         {
5125             VerifyOrQuit(browseCallback->mTtl == 500);
5126         }
5127         else if (browseCallback->mServiceInstance.Matches("mysrv"))
5128         {
5129             VerifyOrQuit(browseCallback->mTtl == 120);
5130         }
5131         else
5132         {
5133             VerifyOrQuit(false);
5134         }
5135 
5136         browseCallback = browseCallback->GetNext();
5137     }
5138 
5139     VerifyOrQuit(browseCallback == nullptr);
5140 
5141     AdvanceTime(5000);
5142 
5143     VerifyOrQuit(sDnsMessages.IsEmpty());
5144 
5145     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5146     Log("Start same browser again and check the returned error.");
5147 
5148     sBrowseCallbacks.Clear();
5149 
5150     VerifyOrQuit(mdns->StartBrowser(browser2) == kErrorAlready);
5151 
5152     AdvanceTime(5000);
5153 
5154     VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5155 
5156     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5157     Log("Send a goodbye response. Validate result callback for both browsers.");
5158 
5159     SendPtrResponse("_srv._udp.local.", "awesome._srv._udp.local.", 0, kInAnswerSection);
5160 
5161     AdvanceTime(1);
5162 
5163     browseCallback = sBrowseCallbacks.GetHead();
5164 
5165     for (uint8_t iter = 0; iter < 2; iter++)
5166     {
5167         VerifyOrQuit(browseCallback != nullptr);
5168 
5169         VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
5170         VerifyOrQuit(!browseCallback->mIsSubType);
5171         VerifyOrQuit(browseCallback->mServiceInstance.Matches("awesome"));
5172         VerifyOrQuit(browseCallback->mTtl == 0);
5173 
5174         browseCallback = browseCallback->GetNext();
5175     }
5176 
5177     VerifyOrQuit(browseCallback == nullptr);
5178 
5179     VerifyOrQuit(sDnsMessages.IsEmpty());
5180 
5181     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5182     Log("Send a response with no changes, validate that no callback is invoked.");
5183 
5184     sBrowseCallbacks.Clear();
5185 
5186     SendPtrResponse("_srv._udp.local.", "mysrv._srv._udp.local.", 120, kInAnswerSection);
5187 
5188     AdvanceTime(1);
5189 
5190     VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5191     VerifyOrQuit(sDnsMessages.IsEmpty());
5192 
5193     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5194     Log("Stop the second browser.");
5195 
5196     sBrowseCallbacks.Clear();
5197 
5198     SuccessOrQuit(mdns->StopBrowser(browser2));
5199 
5200     AdvanceTime(5000);
5201 
5202     VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5203     VerifyOrQuit(sDnsMessages.IsEmpty());
5204 
5205     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5206     Log("Check query is sent at 80 percentage of TTL and then respond to it.");
5207 
5208     // First query should be sent at 80-82% of TTL of 120 second (96.0-98.4 sec).
5209     // We wait for 100 second. Note that 5 seconds already passed in the
5210     // previous step.
5211 
5212     AdvanceTime(91 * 1000 - 1);
5213 
5214     VerifyOrQuit(sDnsMessages.IsEmpty());
5215 
5216     AdvanceTime(4 * 1000 + 1);
5217 
5218     VerifyOrQuit(!sDnsMessages.IsEmpty());
5219     dnsMsg = sDnsMessages.GetHead();
5220     dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5221     dnsMsg->ValidateAsQueryFor(browser);
5222     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5223 
5224     sDnsMessages.Clear();
5225     VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5226 
5227     AdvanceTime(10);
5228 
5229     SendPtrResponse("_srv._udp.local.", "mysrv._srv._udp.local.", 120, kInAnswerSection);
5230 
5231     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5232     Log("Check queries are sent at 80, 85, 90, 95 percentages of TTL.");
5233 
5234     for (uint8_t queryCount = 0; queryCount < kNumRefreshQueries; queryCount++)
5235     {
5236         if (queryCount == 0)
5237         {
5238             // First query is expected in 80-82% of TTL, so
5239             // 80% of 120 = 96.0, 82% of 120 = 98.4
5240 
5241             AdvanceTime(96 * 1000 - 1);
5242         }
5243         else
5244         {
5245             // Next query should happen within 3%-5% of TTL
5246             // from previous query. We wait 3% of TTL here.
5247             AdvanceTime(3600 - 1);
5248         }
5249 
5250         VerifyOrQuit(sDnsMessages.IsEmpty());
5251 
5252         // Wait for 2% of TTL of 120 which is 2.4 sec.
5253 
5254         AdvanceTime(2400 + 1);
5255 
5256         VerifyOrQuit(!sDnsMessages.IsEmpty());
5257         dnsMsg = sDnsMessages.GetHead();
5258         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5259         dnsMsg->ValidateAsQueryFor(browser);
5260         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5261 
5262         sDnsMessages.Clear();
5263         VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5264     }
5265 
5266     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5267     Log("Check TTL timeout and callback result.");
5268 
5269     AdvanceTime(6 * 1000);
5270 
5271     VerifyOrQuit(!sBrowseCallbacks.IsEmpty());
5272 
5273     browseCallback = sBrowseCallbacks.GetHead();
5274     VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
5275     VerifyOrQuit(!browseCallback->mIsSubType);
5276     VerifyOrQuit(browseCallback->mServiceInstance.Matches("mysrv"));
5277     VerifyOrQuit(browseCallback->mTtl == 0);
5278     VerifyOrQuit(browseCallback->GetNext() == nullptr);
5279 
5280     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5281 
5282     sBrowseCallbacks.Clear();
5283     sDnsMessages.Clear();
5284 
5285     AdvanceTime(200 * 1000);
5286 
5287     VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5288     VerifyOrQuit(sDnsMessages.IsEmpty());
5289 
5290     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5291     Log("Send a new response and make sure result callback is invoked");
5292 
5293     SendPtrResponse("_srv._udp.local.", "great._srv._udp.local.", 200, kInAdditionalSection);
5294 
5295     AdvanceTime(1);
5296 
5297     browseCallback = sBrowseCallbacks.GetHead();
5298 
5299     VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
5300     VerifyOrQuit(!browseCallback->mIsSubType);
5301     VerifyOrQuit(browseCallback->mServiceInstance.Matches("great"));
5302     VerifyOrQuit(browseCallback->mTtl == 200);
5303     VerifyOrQuit(browseCallback->GetNext() == nullptr);
5304 
5305     sBrowseCallbacks.Clear();
5306 
5307     AdvanceTime(150 * 1000);
5308 
5309     VerifyOrQuit(sDnsMessages.IsEmpty());
5310     VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5311 
5312     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5313     Log("Stop the browser. There is no active browser for this service. Ensure no queries are sent");
5314 
5315     sBrowseCallbacks.Clear();
5316 
5317     SuccessOrQuit(mdns->StopBrowser(browser));
5318 
5319     AdvanceTime(100 * 1000);
5320 
5321     VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5322     VerifyOrQuit(sDnsMessages.IsEmpty());
5323 
5324     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5325     Log("Start browser again. Validate that initial queries are sent again");
5326 
5327     SuccessOrQuit(mdns->StartBrowser(browser));
5328 
5329     AdvanceTime(125);
5330 
5331     VerifyOrQuit(!sDnsMessages.IsEmpty());
5332     dnsMsg = sDnsMessages.GetHead();
5333     dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5334     dnsMsg->ValidateAsQueryFor(browser);
5335     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5336 
5337     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5338     Log("Send a response after the first initial query");
5339 
5340     sDnsMessages.Clear();
5341 
5342     SendPtrResponse("_srv._udp.local.", "mysrv._srv._udp.local.", 120, kInAnswerSection);
5343 
5344     AdvanceTime(1);
5345 
5346     browseCallback = sBrowseCallbacks.GetHead();
5347 
5348     VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
5349     VerifyOrQuit(!browseCallback->mIsSubType);
5350     VerifyOrQuit(browseCallback->mServiceInstance.Matches("mysrv"));
5351     VerifyOrQuit(browseCallback->mTtl == 120);
5352     VerifyOrQuit(browseCallback->GetNext() == nullptr);
5353 
5354     sBrowseCallbacks.Clear();
5355 
5356     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5357     Log("Validate initial esquires are still sent and include known-answer");
5358 
5359     for (uint8_t queryCount = 1; queryCount < kNumInitalQueries; queryCount++)
5360     {
5361         sDnsMessages.Clear();
5362 
5363         AdvanceTime((1U << (queryCount - 1)) * 1000);
5364 
5365         VerifyOrQuit(!sDnsMessages.IsEmpty());
5366         dnsMsg = sDnsMessages.GetHead();
5367         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
5368         dnsMsg->ValidateAsQueryFor(browser);
5369         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5370     }
5371 
5372     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5373 
5374     sDnsMessages.Clear();
5375     AdvanceTime(50 * 1000);
5376     VerifyOrQuit(sDnsMessages.IsEmpty());
5377 
5378     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
5379     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
5380 
5381     Log("End of test");
5382 
5383     testFreeInstance(sInstance);
5384 }
5385 
TestSrvResolver(void)5386 void TestSrvResolver(void)
5387 {
5388     Core              *mdns = InitTest();
5389     Core::SrvResolver  resolver;
5390     Core::SrvResolver  resolver2;
5391     const DnsMessage  *dnsMsg;
5392     const SrvCallback *srvCallback;
5393     uint16_t           heapAllocations;
5394 
5395     Log("-------------------------------------------------------------------------------------------");
5396     Log("TestSrvResolver");
5397 
5398     AdvanceTime(1);
5399 
5400     heapAllocations = sHeapAllocatedPtrs.GetLength();
5401     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
5402 
5403     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5404     Log("Start a SRV resolver. Validate initial queries.");
5405 
5406     ClearAllBytes(resolver);
5407 
5408     resolver.mServiceInstance = "mysrv";
5409     resolver.mServiceType     = "_srv._udp";
5410     resolver.mInfraIfIndex    = kInfraIfIndex;
5411     resolver.mCallback        = HandleSrvResult;
5412 
5413     sDnsMessages.Clear();
5414     SuccessOrQuit(mdns->StartSrvResolver(resolver));
5415 
5416     for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; queryCount++)
5417     {
5418         sDnsMessages.Clear();
5419 
5420         AdvanceTime((queryCount == 0) ? 125 : (1U << (queryCount - 1)) * 1000);
5421 
5422         VerifyOrQuit(!sDnsMessages.IsEmpty());
5423         dnsMsg = sDnsMessages.GetHead();
5424         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5425         dnsMsg->ValidateAsQueryFor(resolver);
5426         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5427     }
5428 
5429     sDnsMessages.Clear();
5430 
5431     AdvanceTime(20 * 1000);
5432     VerifyOrQuit(sDnsMessages.IsEmpty());
5433 
5434     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5435     Log("Send a response. Validate callback result.");
5436 
5437     sSrvCallbacks.Clear();
5438 
5439     SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 0, 1, 120, kInAnswerSection);
5440 
5441     AdvanceTime(1);
5442 
5443     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5444     srvCallback = sSrvCallbacks.GetHead();
5445     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5446     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5447     VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
5448     VerifyOrQuit(srvCallback->mPort == 1234);
5449     VerifyOrQuit(srvCallback->mPriority == 0);
5450     VerifyOrQuit(srvCallback->mWeight == 1);
5451     VerifyOrQuit(srvCallback->mTtl == 120);
5452     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5453 
5454     VerifyOrQuit(sDnsMessages.IsEmpty());
5455 
5456     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5457     Log("Send an updated response changing host name. Validate callback result.");
5458 
5459     AdvanceTime(1000);
5460 
5461     sSrvCallbacks.Clear();
5462 
5463     SendSrvResponse("mysrv._srv._udp.local.", "myhost2.local.", 1234, 0, 1, 120, kInAnswerSection);
5464 
5465     AdvanceTime(1);
5466 
5467     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5468     srvCallback = sSrvCallbacks.GetHead();
5469     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5470     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5471     VerifyOrQuit(srvCallback->mHostName.Matches("myhost2"));
5472     VerifyOrQuit(srvCallback->mPort == 1234);
5473     VerifyOrQuit(srvCallback->mPriority == 0);
5474     VerifyOrQuit(srvCallback->mWeight == 1);
5475     VerifyOrQuit(srvCallback->mTtl == 120);
5476     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5477 
5478     VerifyOrQuit(sDnsMessages.IsEmpty());
5479 
5480     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5481     Log("Send an updated response changing port. Validate callback result.");
5482 
5483     AdvanceTime(1000);
5484 
5485     sSrvCallbacks.Clear();
5486 
5487     SendSrvResponse("mysrv._srv._udp.local.", "myhost2.local.", 4567, 0, 1, 120, kInAnswerSection);
5488 
5489     AdvanceTime(1);
5490 
5491     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5492     srvCallback = sSrvCallbacks.GetHead();
5493     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5494     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5495     VerifyOrQuit(srvCallback->mHostName.Matches("myhost2"));
5496     VerifyOrQuit(srvCallback->mPort == 4567);
5497     VerifyOrQuit(srvCallback->mPriority == 0);
5498     VerifyOrQuit(srvCallback->mWeight == 1);
5499     VerifyOrQuit(srvCallback->mTtl == 120);
5500     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5501 
5502     VerifyOrQuit(sDnsMessages.IsEmpty());
5503 
5504     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5505     Log("Send an updated response changing TTL. Validate callback result.");
5506 
5507     AdvanceTime(1000);
5508 
5509     sSrvCallbacks.Clear();
5510 
5511     SendSrvResponse("mysrv._srv._udp.local.", "myhost2.local.", 4567, 0, 1, 0, kInAnswerSection);
5512 
5513     AdvanceTime(1);
5514 
5515     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5516     srvCallback = sSrvCallbacks.GetHead();
5517     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5518     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5519     VerifyOrQuit(srvCallback->mHostName.Matches(""));
5520     VerifyOrQuit(srvCallback->mPort == 4567);
5521     VerifyOrQuit(srvCallback->mPriority == 0);
5522     VerifyOrQuit(srvCallback->mWeight == 1);
5523     VerifyOrQuit(srvCallback->mTtl == 0);
5524     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5525 
5526     VerifyOrQuit(sDnsMessages.IsEmpty());
5527 
5528     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5529     Log("Send an updated response changing a bunch of things. Validate callback result.");
5530 
5531     AdvanceTime(1000);
5532 
5533     sSrvCallbacks.Clear();
5534 
5535     SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
5536 
5537     AdvanceTime(1);
5538 
5539     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5540     srvCallback = sSrvCallbacks.GetHead();
5541     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5542     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5543     VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
5544     VerifyOrQuit(srvCallback->mPort == 1234);
5545     VerifyOrQuit(srvCallback->mPriority == 2);
5546     VerifyOrQuit(srvCallback->mWeight == 3);
5547     VerifyOrQuit(srvCallback->mTtl == 120);
5548     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5549 
5550     VerifyOrQuit(sDnsMessages.IsEmpty());
5551 
5552     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5553     Log("Send a response with no changes. Validate callback is not invoked.");
5554 
5555     AdvanceTime(1000);
5556 
5557     sSrvCallbacks.Clear();
5558 
5559     SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
5560 
5561     AdvanceTime(1);
5562 
5563     VerifyOrQuit(sSrvCallbacks.IsEmpty());
5564     VerifyOrQuit(sDnsMessages.IsEmpty());
5565 
5566     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5567     Log("Start another resolver for the same service and different callback. Validate results.");
5568 
5569     ClearAllBytes(resolver2);
5570 
5571     resolver2.mServiceInstance = "mysrv";
5572     resolver2.mServiceType     = "_srv._udp";
5573     resolver2.mInfraIfIndex    = kInfraIfIndex;
5574     resolver2.mCallback        = HandleSrvResultAlternate;
5575 
5576     sSrvCallbacks.Clear();
5577 
5578     SuccessOrQuit(mdns->StartSrvResolver(resolver2));
5579 
5580     AdvanceTime(1);
5581 
5582     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5583     srvCallback = sSrvCallbacks.GetHead();
5584     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5585     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5586     VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
5587     VerifyOrQuit(srvCallback->mPort == 1234);
5588     VerifyOrQuit(srvCallback->mPriority == 2);
5589     VerifyOrQuit(srvCallback->mWeight == 3);
5590     VerifyOrQuit(srvCallback->mTtl == 120);
5591     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5592 
5593     VerifyOrQuit(sDnsMessages.IsEmpty());
5594 
5595     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5596     Log("Start same resolver again and check the returned error.");
5597 
5598     sSrvCallbacks.Clear();
5599 
5600     VerifyOrQuit(mdns->StartSrvResolver(resolver2) == kErrorAlready);
5601 
5602     AdvanceTime(5000);
5603 
5604     VerifyOrQuit(sSrvCallbacks.IsEmpty());
5605 
5606     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5607     Log("Check query is sent at 80 percentage of TTL and then respond to it.");
5608 
5609     SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
5610 
5611     // First query should be sent at 80-82% of TTL of 120 second (96.0-98.4 sec).
5612     // We wait for 100 second. Note that 5 seconds already passed in the
5613     // previous step.
5614 
5615     AdvanceTime(96 * 1000 - 1);
5616 
5617     VerifyOrQuit(sDnsMessages.IsEmpty());
5618 
5619     AdvanceTime(4 * 1000 + 1);
5620 
5621     VerifyOrQuit(!sDnsMessages.IsEmpty());
5622     dnsMsg = sDnsMessages.GetHead();
5623     dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5624     dnsMsg->ValidateAsQueryFor(resolver);
5625     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5626 
5627     sDnsMessages.Clear();
5628     VerifyOrQuit(sSrvCallbacks.IsEmpty());
5629 
5630     AdvanceTime(10);
5631 
5632     SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
5633 
5634     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5635     Log("Check queries are sent at 80, 85, 90, 95 percentages of TTL.");
5636 
5637     for (uint8_t queryCount = 0; queryCount < kNumRefreshQueries; queryCount++)
5638     {
5639         if (queryCount == 0)
5640         {
5641             // First query is expected in 80-82% of TTL, so
5642             // 80% of 120 = 96.0, 82% of 120 = 98.4
5643 
5644             AdvanceTime(96 * 1000 - 1);
5645         }
5646         else
5647         {
5648             // Next query should happen within 3%-5% of TTL
5649             // from previous query. We wait 3% of TTL here.
5650             AdvanceTime(3600 - 1);
5651         }
5652 
5653         VerifyOrQuit(sDnsMessages.IsEmpty());
5654 
5655         // Wait for 2% of TTL of 120 which is 2.4 sec.
5656 
5657         AdvanceTime(2400 + 1);
5658 
5659         VerifyOrQuit(!sDnsMessages.IsEmpty());
5660         dnsMsg = sDnsMessages.GetHead();
5661         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5662         dnsMsg->ValidateAsQueryFor(resolver);
5663         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5664 
5665         sDnsMessages.Clear();
5666         VerifyOrQuit(sSrvCallbacks.IsEmpty());
5667     }
5668 
5669     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5670     Log("Check TTL timeout and callback result.");
5671 
5672     AdvanceTime(6 * 1000);
5673 
5674     srvCallback = sSrvCallbacks.GetHead();
5675 
5676     for (uint8_t iter = 0; iter < 2; iter++)
5677     {
5678         VerifyOrQuit(srvCallback != nullptr);
5679         VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5680         VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5681         VerifyOrQuit(srvCallback->mTtl == 0);
5682         srvCallback = srvCallback->GetNext();
5683     }
5684 
5685     VerifyOrQuit(srvCallback == nullptr);
5686 
5687     VerifyOrQuit(sDnsMessages.IsEmpty());
5688 
5689     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5690 
5691     sSrvCallbacks.Clear();
5692     sDnsMessages.Clear();
5693 
5694     AdvanceTime(200 * 1000);
5695 
5696     VerifyOrQuit(sSrvCallbacks.IsEmpty());
5697     VerifyOrQuit(sDnsMessages.IsEmpty());
5698 
5699     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5700     Log("Stop the second resolver");
5701 
5702     sSrvCallbacks.Clear();
5703 
5704     SuccessOrQuit(mdns->StopSrvResolver(resolver2));
5705 
5706     AdvanceTime(100 * 1000);
5707 
5708     VerifyOrQuit(sSrvCallbacks.IsEmpty());
5709     VerifyOrQuit(sDnsMessages.IsEmpty());
5710 
5711     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5712     Log("Send a new response and make sure result callback is invoked");
5713 
5714     SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
5715 
5716     AdvanceTime(1);
5717 
5718     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5719     srvCallback = sSrvCallbacks.GetHead();
5720     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5721     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5722     VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
5723     VerifyOrQuit(srvCallback->mPort == 1234);
5724     VerifyOrQuit(srvCallback->mPriority == 2);
5725     VerifyOrQuit(srvCallback->mWeight == 3);
5726     VerifyOrQuit(srvCallback->mTtl == 120);
5727     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5728 
5729     VerifyOrQuit(sDnsMessages.IsEmpty());
5730 
5731     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5732     Log("Stop the resolver. There is no active resolver. Ensure no queries are sent");
5733 
5734     sSrvCallbacks.Clear();
5735 
5736     SuccessOrQuit(mdns->StopSrvResolver(resolver));
5737 
5738     AdvanceTime(20 * 1000);
5739 
5740     VerifyOrQuit(sSrvCallbacks.IsEmpty());
5741     VerifyOrQuit(sDnsMessages.IsEmpty());
5742 
5743     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5744     Log("Restart the resolver with more than half of TTL remaining.");
5745     Log("Ensure cached entry is reported in the result callback and no queries are sent.");
5746 
5747     SuccessOrQuit(mdns->StartSrvResolver(resolver));
5748 
5749     AdvanceTime(1);
5750 
5751     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5752     srvCallback = sSrvCallbacks.GetHead();
5753     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5754     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5755     VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
5756     VerifyOrQuit(srvCallback->mPort == 1234);
5757     VerifyOrQuit(srvCallback->mPriority == 2);
5758     VerifyOrQuit(srvCallback->mWeight == 3);
5759     VerifyOrQuit(srvCallback->mTtl == 120);
5760     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5761 
5762     VerifyOrQuit(sDnsMessages.IsEmpty());
5763 
5764     AdvanceTime(20 * 1000);
5765 
5766     VerifyOrQuit(sDnsMessages.IsEmpty());
5767 
5768     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5769     Log("Stop and start the resolver again after less than half TTL remaining.");
5770     Log("Ensure cached entry is still reported in the result callback but queries should be sent");
5771 
5772     sSrvCallbacks.Clear();
5773 
5774     SuccessOrQuit(mdns->StopSrvResolver(resolver));
5775 
5776     AdvanceTime(25 * 1000);
5777 
5778     SuccessOrQuit(mdns->StartSrvResolver(resolver));
5779 
5780     AdvanceTime(1);
5781 
5782     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5783     srvCallback = sSrvCallbacks.GetHead();
5784     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5785     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5786     VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
5787     VerifyOrQuit(srvCallback->mPort == 1234);
5788     VerifyOrQuit(srvCallback->mPriority == 2);
5789     VerifyOrQuit(srvCallback->mWeight == 3);
5790     VerifyOrQuit(srvCallback->mTtl == 120);
5791     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5792 
5793     sSrvCallbacks.Clear();
5794 
5795     AdvanceTime(15 * 1000);
5796 
5797     dnsMsg = sDnsMessages.GetHead();
5798 
5799     for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; queryCount++)
5800     {
5801         VerifyOrQuit(dnsMsg != nullptr);
5802         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5803         dnsMsg->ValidateAsQueryFor(resolver);
5804         dnsMsg = dnsMsg->GetNext();
5805     }
5806 
5807     VerifyOrQuit(dnsMsg == nullptr);
5808 
5809     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5810 
5811     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
5812     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
5813 
5814     Log("End of test");
5815 
5816     testFreeInstance(sInstance);
5817 }
5818 
TestTxtResolver(void)5819 void TestTxtResolver(void)
5820 {
5821     Core              *mdns = InitTest();
5822     Core::TxtResolver  resolver;
5823     Core::TxtResolver  resolver2;
5824     const DnsMessage  *dnsMsg;
5825     const TxtCallback *txtCallback;
5826     uint16_t           heapAllocations;
5827 
5828     Log("-------------------------------------------------------------------------------------------");
5829     Log("TestTxtResolver");
5830 
5831     AdvanceTime(1);
5832 
5833     heapAllocations = sHeapAllocatedPtrs.GetLength();
5834     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
5835 
5836     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5837     Log("Start a TXT resolver. Validate initial queries.");
5838 
5839     ClearAllBytes(resolver);
5840 
5841     resolver.mServiceInstance = "mysrv";
5842     resolver.mServiceType     = "_srv._udp";
5843     resolver.mInfraIfIndex    = kInfraIfIndex;
5844     resolver.mCallback        = HandleTxtResult;
5845 
5846     sDnsMessages.Clear();
5847     SuccessOrQuit(mdns->StartTxtResolver(resolver));
5848 
5849     for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; queryCount++)
5850     {
5851         sDnsMessages.Clear();
5852 
5853         AdvanceTime((queryCount == 0) ? 125 : (1U << (queryCount - 1)) * 1000);
5854 
5855         VerifyOrQuit(!sDnsMessages.IsEmpty());
5856         dnsMsg = sDnsMessages.GetHead();
5857         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5858         dnsMsg->ValidateAsQueryFor(resolver);
5859         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5860     }
5861 
5862     sDnsMessages.Clear();
5863 
5864     AdvanceTime(20 * 1000);
5865     VerifyOrQuit(sDnsMessages.IsEmpty());
5866 
5867     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5868     Log("Send a response. Validate callback result.");
5869 
5870     sTxtCallbacks.Clear();
5871 
5872     SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
5873 
5874     AdvanceTime(1);
5875 
5876     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
5877     txtCallback = sTxtCallbacks.GetHead();
5878     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5879     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
5880     VerifyOrQuit(txtCallback->Matches(kTxtData1));
5881     VerifyOrQuit(txtCallback->mTtl == 120);
5882     VerifyOrQuit(txtCallback->GetNext() == nullptr);
5883 
5884     VerifyOrQuit(sDnsMessages.IsEmpty());
5885 
5886     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5887     Log("Send an updated response changing TXT data. Validate callback result.");
5888 
5889     AdvanceTime(1000);
5890 
5891     sTxtCallbacks.Clear();
5892 
5893     SendTxtResponse("mysrv._srv._udp.local.", kTxtData2, sizeof(kTxtData2), 120, kInAnswerSection);
5894 
5895     AdvanceTime(1);
5896 
5897     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
5898     txtCallback = sTxtCallbacks.GetHead();
5899     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5900     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
5901     VerifyOrQuit(txtCallback->Matches(kTxtData2));
5902     VerifyOrQuit(txtCallback->mTtl == 120);
5903     VerifyOrQuit(txtCallback->GetNext() == nullptr);
5904 
5905     VerifyOrQuit(sDnsMessages.IsEmpty());
5906 
5907     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5908     Log("Send an updated response changing TXT data to empty. Validate callback result.");
5909 
5910     AdvanceTime(1000);
5911 
5912     sTxtCallbacks.Clear();
5913 
5914     SendTxtResponse("mysrv._srv._udp.local.", kEmptyTxtData, sizeof(kEmptyTxtData), 120, kInAnswerSection);
5915 
5916     AdvanceTime(1);
5917 
5918     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
5919     txtCallback = sTxtCallbacks.GetHead();
5920     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5921     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
5922     VerifyOrQuit(txtCallback->Matches(kEmptyTxtData));
5923     VerifyOrQuit(txtCallback->mTtl == 120);
5924     VerifyOrQuit(txtCallback->GetNext() == nullptr);
5925 
5926     VerifyOrQuit(sDnsMessages.IsEmpty());
5927 
5928     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5929     Log("Send an updated response changing TTL. Validate callback result.");
5930 
5931     AdvanceTime(1000);
5932 
5933     sTxtCallbacks.Clear();
5934 
5935     SendTxtResponse("mysrv._srv._udp.local.", kEmptyTxtData, sizeof(kEmptyTxtData), 500, kInAnswerSection);
5936 
5937     AdvanceTime(1);
5938 
5939     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
5940     txtCallback = sTxtCallbacks.GetHead();
5941     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5942     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
5943     VerifyOrQuit(txtCallback->Matches(kEmptyTxtData));
5944     VerifyOrQuit(txtCallback->mTtl == 500);
5945     VerifyOrQuit(txtCallback->GetNext() == nullptr);
5946 
5947     VerifyOrQuit(sDnsMessages.IsEmpty());
5948 
5949     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5950     Log("Send an updated response with zero TTL. Validate callback result.");
5951 
5952     AdvanceTime(1000);
5953 
5954     sTxtCallbacks.Clear();
5955 
5956     SendTxtResponse("mysrv._srv._udp.local.", kEmptyTxtData, sizeof(kEmptyTxtData), 0, kInAnswerSection);
5957 
5958     AdvanceTime(1);
5959 
5960     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
5961     txtCallback = sTxtCallbacks.GetHead();
5962     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5963     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
5964     VerifyOrQuit(txtCallback->mTtl == 0);
5965     VerifyOrQuit(txtCallback->GetNext() == nullptr);
5966 
5967     VerifyOrQuit(sDnsMessages.IsEmpty());
5968 
5969     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5970     Log("Send an updated response. Validate callback result.");
5971 
5972     sTxtCallbacks.Clear();
5973     AdvanceTime(100 * 1000);
5974 
5975     SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
5976 
5977     AdvanceTime(1);
5978 
5979     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
5980     txtCallback = sTxtCallbacks.GetHead();
5981     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5982     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
5983     VerifyOrQuit(txtCallback->Matches(kTxtData1));
5984     VerifyOrQuit(txtCallback->mTtl == 120);
5985     VerifyOrQuit(txtCallback->GetNext() == nullptr);
5986 
5987     VerifyOrQuit(sDnsMessages.IsEmpty());
5988 
5989     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5990     Log("Send a response with no changes. Validate callback is not invoked.");
5991 
5992     AdvanceTime(1000);
5993 
5994     sTxtCallbacks.Clear();
5995 
5996     SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
5997 
5998     AdvanceTime(100);
5999 
6000     VerifyOrQuit(sTxtCallbacks.IsEmpty());
6001     VerifyOrQuit(sDnsMessages.IsEmpty());
6002 
6003     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6004     Log("Start another resolver for the same service and different callback. Validate results.");
6005 
6006     resolver2.mServiceInstance = "mysrv";
6007     resolver2.mServiceType     = "_srv._udp";
6008     resolver2.mInfraIfIndex    = kInfraIfIndex;
6009     resolver2.mCallback        = HandleTxtResultAlternate;
6010 
6011     sTxtCallbacks.Clear();
6012 
6013     SuccessOrQuit(mdns->StartTxtResolver(resolver2));
6014 
6015     AdvanceTime(1);
6016 
6017     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
6018     txtCallback = sTxtCallbacks.GetHead();
6019     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
6020     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
6021     VerifyOrQuit(txtCallback->Matches(kTxtData1));
6022     VerifyOrQuit(txtCallback->mTtl == 120);
6023     VerifyOrQuit(txtCallback->GetNext() == nullptr);
6024 
6025     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6026     Log("Start same resolver again and check the returned error.");
6027 
6028     sTxtCallbacks.Clear();
6029 
6030     VerifyOrQuit(mdns->StartTxtResolver(resolver2) == kErrorAlready);
6031 
6032     AdvanceTime(5000);
6033 
6034     VerifyOrQuit(sTxtCallbacks.IsEmpty());
6035 
6036     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6037     Log("Check query is sent at 80 percentage of TTL and then respond to it.");
6038 
6039     SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
6040 
6041     // First query should be sent at 80-82% of TTL of 120 second (96.0-98.4 sec).
6042     // We wait for 100 second. Note that 5 seconds already passed in the
6043     // previous step.
6044 
6045     AdvanceTime(96 * 1000 - 1);
6046 
6047     VerifyOrQuit(sDnsMessages.IsEmpty());
6048 
6049     AdvanceTime(4 * 1000 + 1);
6050 
6051     VerifyOrQuit(!sDnsMessages.IsEmpty());
6052     dnsMsg = sDnsMessages.GetHead();
6053     dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
6054     dnsMsg->ValidateAsQueryFor(resolver);
6055     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
6056 
6057     sDnsMessages.Clear();
6058     VerifyOrQuit(sTxtCallbacks.IsEmpty());
6059 
6060     AdvanceTime(10);
6061 
6062     SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
6063 
6064     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6065     Log("Check queries are sent at 80, 85, 90, 95 percentages of TTL.");
6066 
6067     for (uint8_t queryCount = 0; queryCount < kNumRefreshQueries; queryCount++)
6068     {
6069         if (queryCount == 0)
6070         {
6071             // First query is expected in 80-82% of TTL, so
6072             // 80% of 120 = 96.0, 82% of 120 = 98.4
6073 
6074             AdvanceTime(96 * 1000 - 1);
6075         }
6076         else
6077         {
6078             // Next query should happen within 3%-5% of TTL
6079             // from previous query. We wait 3% of TTL here.
6080             AdvanceTime(3600 - 1);
6081         }
6082 
6083         VerifyOrQuit(sDnsMessages.IsEmpty());
6084 
6085         // Wait for 2% of TTL of 120 which is 2.4 sec.
6086 
6087         AdvanceTime(2400 + 1);
6088 
6089         VerifyOrQuit(!sDnsMessages.IsEmpty());
6090         dnsMsg = sDnsMessages.GetHead();
6091         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
6092         dnsMsg->ValidateAsQueryFor(resolver);
6093         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
6094 
6095         sDnsMessages.Clear();
6096         VerifyOrQuit(sTxtCallbacks.IsEmpty());
6097     }
6098 
6099     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6100     Log("Check TTL timeout and callback result.");
6101 
6102     AdvanceTime(6 * 1000);
6103 
6104     txtCallback = sTxtCallbacks.GetHead();
6105 
6106     for (uint8_t iter = 0; iter < 2; iter++)
6107     {
6108         VerifyOrQuit(txtCallback != nullptr);
6109         VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
6110         VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
6111         VerifyOrQuit(txtCallback->mTtl == 0);
6112         txtCallback = txtCallback->GetNext();
6113     }
6114 
6115     VerifyOrQuit(txtCallback == nullptr);
6116 
6117     VerifyOrQuit(sDnsMessages.IsEmpty());
6118 
6119     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6120 
6121     sTxtCallbacks.Clear();
6122     sDnsMessages.Clear();
6123 
6124     AdvanceTime(200 * 1000);
6125 
6126     VerifyOrQuit(sTxtCallbacks.IsEmpty());
6127     VerifyOrQuit(sDnsMessages.IsEmpty());
6128 
6129     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6130     Log("Stop the second resolver");
6131 
6132     sTxtCallbacks.Clear();
6133 
6134     SuccessOrQuit(mdns->StopTxtResolver(resolver2));
6135 
6136     AdvanceTime(100 * 1000);
6137 
6138     VerifyOrQuit(sTxtCallbacks.IsEmpty());
6139     VerifyOrQuit(sDnsMessages.IsEmpty());
6140 
6141     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6142     Log("Send a new response and make sure result callback is invoked");
6143 
6144     SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
6145 
6146     AdvanceTime(1);
6147 
6148     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
6149     txtCallback = sTxtCallbacks.GetHead();
6150     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
6151     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
6152     VerifyOrQuit(txtCallback->Matches(kTxtData1));
6153     VerifyOrQuit(txtCallback->mTtl == 120);
6154     VerifyOrQuit(txtCallback->GetNext() == nullptr);
6155 
6156     VerifyOrQuit(sDnsMessages.IsEmpty());
6157 
6158     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6159     Log("Stop the resolver. There is no active resolver. Ensure no queries are sent");
6160 
6161     sTxtCallbacks.Clear();
6162 
6163     SuccessOrQuit(mdns->StopTxtResolver(resolver));
6164 
6165     AdvanceTime(20 * 1000);
6166 
6167     VerifyOrQuit(sTxtCallbacks.IsEmpty());
6168     VerifyOrQuit(sDnsMessages.IsEmpty());
6169 
6170     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6171     Log("Restart the resolver with more than half of TTL remaining.");
6172     Log("Ensure cached entry is reported in the result callback and no queries are sent.");
6173 
6174     SuccessOrQuit(mdns->StartTxtResolver(resolver));
6175 
6176     AdvanceTime(1);
6177 
6178     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
6179     txtCallback = sTxtCallbacks.GetHead();
6180     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
6181     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
6182     VerifyOrQuit(txtCallback->Matches(kTxtData1));
6183     VerifyOrQuit(txtCallback->mTtl == 120);
6184     VerifyOrQuit(txtCallback->GetNext() == nullptr);
6185 
6186     VerifyOrQuit(sDnsMessages.IsEmpty());
6187 
6188     AdvanceTime(20 * 1000);
6189 
6190     VerifyOrQuit(sDnsMessages.IsEmpty());
6191 
6192     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6193     Log("Stop and start the resolver again after less than half TTL remaining.");
6194     Log("Ensure cached entry is still reported in the result callback but queries should be sent");
6195 
6196     sTxtCallbacks.Clear();
6197 
6198     SuccessOrQuit(mdns->StopTxtResolver(resolver));
6199 
6200     AdvanceTime(25 * 1000);
6201 
6202     SuccessOrQuit(mdns->StartTxtResolver(resolver));
6203 
6204     AdvanceTime(1);
6205 
6206     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
6207     txtCallback = sTxtCallbacks.GetHead();
6208     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
6209     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
6210     VerifyOrQuit(txtCallback->Matches(kTxtData1));
6211     VerifyOrQuit(txtCallback->mTtl == 120);
6212     VerifyOrQuit(txtCallback->GetNext() == nullptr);
6213 
6214     sTxtCallbacks.Clear();
6215 
6216     AdvanceTime(15 * 1000);
6217 
6218     dnsMsg = sDnsMessages.GetHead();
6219 
6220     for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; queryCount++)
6221     {
6222         VerifyOrQuit(dnsMsg != nullptr);
6223         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
6224         dnsMsg->ValidateAsQueryFor(resolver);
6225         dnsMsg = dnsMsg->GetNext();
6226     }
6227 
6228     VerifyOrQuit(dnsMsg == nullptr);
6229 
6230     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6231 
6232     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
6233     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
6234 
6235     Log("End of test");
6236 
6237     testFreeInstance(sInstance);
6238 }
6239 
TestIp6AddrResolver(void)6240 void TestIp6AddrResolver(void)
6241 {
6242     Core                 *mdns = InitTest();
6243     Core::AddressResolver resolver;
6244     Core::AddressResolver resolver2;
6245     AddrAndTtl            addrs[5];
6246     const DnsMessage     *dnsMsg;
6247     const AddrCallback   *addrCallback;
6248     uint16_t              heapAllocations;
6249 
6250     Log("-------------------------------------------------------------------------------------------");
6251     Log("TestIp6AddrResolver");
6252 
6253     AdvanceTime(1);
6254 
6255     heapAllocations = sHeapAllocatedPtrs.GetLength();
6256     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
6257 
6258     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6259     Log("Start an IPv6 address resolver. Validate initial queries.");
6260 
6261     ClearAllBytes(resolver);
6262 
6263     resolver.mHostName     = "myhost";
6264     resolver.mInfraIfIndex = kInfraIfIndex;
6265     resolver.mCallback     = HandleAddrResult;
6266 
6267     sDnsMessages.Clear();
6268     SuccessOrQuit(mdns->StartIp6AddressResolver(resolver));
6269 
6270     for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; queryCount++)
6271     {
6272         sDnsMessages.Clear();
6273 
6274         AdvanceTime((queryCount == 0) ? 125 : (1U << (queryCount - 1)) * 1000);
6275 
6276         VerifyOrQuit(!sDnsMessages.IsEmpty());
6277         dnsMsg = sDnsMessages.GetHead();
6278         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
6279         dnsMsg->ValidateAsQueryFor(resolver);
6280         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
6281     }
6282 
6283     sDnsMessages.Clear();
6284 
6285     AdvanceTime(20 * 1000);
6286     VerifyOrQuit(sDnsMessages.IsEmpty());
6287 
6288     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6289     Log("Send a response. Validate callback result.");
6290 
6291     sAddrCallbacks.Clear();
6292 
6293     SuccessOrQuit(addrs[0].mAddress.FromString("fd00::1"));
6294     addrs[0].mTtl = 120;
6295 
6296     SendHostAddrResponse("myhost.local.", addrs, 1, /* aCachFlush */ true, kInAnswerSection);
6297 
6298     AdvanceTime(1);
6299 
6300     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6301     addrCallback = sAddrCallbacks.GetHead();
6302     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6303     VerifyOrQuit(addrCallback->Matches(addrs, 1));
6304     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6305 
6306     VerifyOrQuit(sDnsMessages.IsEmpty());
6307 
6308     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6309     Log("Send an updated response adding a new address. Validate callback result.");
6310 
6311     SuccessOrQuit(addrs[1].mAddress.FromString("fd00::2"));
6312     addrs[1].mTtl = 120;
6313 
6314     AdvanceTime(1000);
6315 
6316     sAddrCallbacks.Clear();
6317 
6318     SendHostAddrResponse("myhost.local.", addrs, 2, /* aCachFlush */ true, kInAnswerSection);
6319 
6320     AdvanceTime(1);
6321 
6322     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6323     addrCallback = sAddrCallbacks.GetHead();
6324     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6325     VerifyOrQuit(addrCallback->Matches(addrs, 2));
6326     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6327 
6328     VerifyOrQuit(sDnsMessages.IsEmpty());
6329 
6330     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6331     Log("Send an updated response adding and removing addresses. Validate callback result.");
6332 
6333     SuccessOrQuit(addrs[0].mAddress.FromString("fd00::2"));
6334     SuccessOrQuit(addrs[1].mAddress.FromString("fd00::aa"));
6335     SuccessOrQuit(addrs[2].mAddress.FromString("fe80::bb"));
6336     addrs[0].mTtl = 120;
6337     addrs[1].mTtl = 120;
6338     addrs[2].mTtl = 120;
6339 
6340     AdvanceTime(1000);
6341 
6342     sAddrCallbacks.Clear();
6343 
6344     SendHostAddrResponse("myhost.local.", addrs, 3, /* aCachFlush */ true, kInAnswerSection);
6345 
6346     AdvanceTime(1);
6347 
6348     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6349     addrCallback = sAddrCallbacks.GetHead();
6350     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6351     VerifyOrQuit(addrCallback->Matches(addrs, 3));
6352     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6353 
6354     VerifyOrQuit(sDnsMessages.IsEmpty());
6355 
6356     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6357     Log("Send a response without cache flush adding an address. Validate callback result.");
6358 
6359     SuccessOrQuit(addrs[3].mAddress.FromString("fd00::3"));
6360     addrs[3].mTtl = 500;
6361 
6362     AdvanceTime(1000);
6363 
6364     sAddrCallbacks.Clear();
6365 
6366     SendHostAddrResponse("myhost.local.", &addrs[3], 1, /* aCachFlush */ false, kInAnswerSection);
6367 
6368     AdvanceTime(1);
6369 
6370     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6371     addrCallback = sAddrCallbacks.GetHead();
6372     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6373     VerifyOrQuit(addrCallback->Matches(addrs, 4));
6374     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6375 
6376     VerifyOrQuit(sDnsMessages.IsEmpty());
6377 
6378     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6379     Log("Send a response without cache flush with existing addresses. Validate that callback is not called.");
6380 
6381     AdvanceTime(1000);
6382 
6383     sAddrCallbacks.Clear();
6384 
6385     SendHostAddrResponse("myhost.local.", &addrs[2], 2, /* aCachFlush */ false, kInAnswerSection);
6386 
6387     AdvanceTime(1);
6388 
6389     VerifyOrQuit(sAddrCallbacks.IsEmpty());
6390     VerifyOrQuit(sDnsMessages.IsEmpty());
6391 
6392     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6393     Log("Send a response without no changes to the list. Validate that callback is not called");
6394 
6395     AdvanceTime(1000);
6396 
6397     sAddrCallbacks.Clear();
6398 
6399     SendHostAddrResponse("myhost.local.", addrs, 4, /* aCachFlush */ true, kInAdditionalSection);
6400 
6401     AdvanceTime(1);
6402 
6403     VerifyOrQuit(sAddrCallbacks.IsEmpty());
6404     VerifyOrQuit(sDnsMessages.IsEmpty());
6405 
6406     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6407     Log("Send a response without cache flush updating TTL of existing address. Validate callback result.");
6408 
6409     addrs[3].mTtl = 200;
6410 
6411     AdvanceTime(1000);
6412 
6413     sAddrCallbacks.Clear();
6414 
6415     SendHostAddrResponse("myhost.local.", &addrs[3], 1, /* aCachFlush */ false, kInAnswerSection);
6416 
6417     AdvanceTime(1);
6418 
6419     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6420     addrCallback = sAddrCallbacks.GetHead();
6421     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6422     VerifyOrQuit(addrCallback->Matches(addrs, 4));
6423     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6424 
6425     VerifyOrQuit(sDnsMessages.IsEmpty());
6426 
6427     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6428     Log("Send a response without cache flush removing an address (zero TTL). Validate callback result.");
6429 
6430     addrs[3].mTtl = 0;
6431 
6432     AdvanceTime(1000);
6433 
6434     sAddrCallbacks.Clear();
6435 
6436     SendHostAddrResponse("myhost.local.", &addrs[3], 1, /* aCachFlush */ false, kInAnswerSection);
6437 
6438     AdvanceTime(1);
6439 
6440     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6441     addrCallback = sAddrCallbacks.GetHead();
6442     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6443     VerifyOrQuit(addrCallback->Matches(addrs, 3));
6444     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6445 
6446     VerifyOrQuit(sDnsMessages.IsEmpty());
6447 
6448     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6449     Log("Send a response with cache flush removing all addresses. Validate callback result.");
6450 
6451     addrs[0].mTtl = 0;
6452 
6453     AdvanceTime(1000);
6454 
6455     sAddrCallbacks.Clear();
6456 
6457     SendHostAddrResponse("myhost.local.", addrs, 1, /* aCachFlush */ true, kInAnswerSection);
6458 
6459     AdvanceTime(1);
6460 
6461     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6462     addrCallback = sAddrCallbacks.GetHead();
6463     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6464     VerifyOrQuit(addrCallback->Matches(addrs, 0));
6465     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6466 
6467     VerifyOrQuit(sDnsMessages.IsEmpty());
6468 
6469     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6470     Log("Send a response with addresses with different TTL. Validate callback result");
6471 
6472     SuccessOrQuit(addrs[0].mAddress.FromString("fd00::00"));
6473     SuccessOrQuit(addrs[1].mAddress.FromString("fd00::11"));
6474     SuccessOrQuit(addrs[2].mAddress.FromString("fe80::22"));
6475     SuccessOrQuit(addrs[3].mAddress.FromString("fe80::33"));
6476     addrs[0].mTtl = 120;
6477     addrs[1].mTtl = 800;
6478     addrs[2].mTtl = 2000;
6479     addrs[3].mTtl = 8000;
6480 
6481     AdvanceTime(5 * 1000);
6482 
6483     sAddrCallbacks.Clear();
6484 
6485     SendHostAddrResponse("myhost.local.", addrs, 4, /* aCachFlush */ true, kInAnswerSection);
6486 
6487     AdvanceTime(1);
6488 
6489     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6490     addrCallback = sAddrCallbacks.GetHead();
6491     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6492     VerifyOrQuit(addrCallback->Matches(addrs, 4));
6493     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6494 
6495     VerifyOrQuit(sDnsMessages.IsEmpty());
6496 
6497     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6498     Log("Start another resolver for the same host and different callback. Validate results.");
6499 
6500     resolver2.mHostName     = "myhost";
6501     resolver2.mInfraIfIndex = kInfraIfIndex;
6502     resolver2.mCallback     = HandleAddrResultAlternate;
6503 
6504     sAddrCallbacks.Clear();
6505 
6506     SuccessOrQuit(mdns->StartIp6AddressResolver(resolver2));
6507 
6508     AdvanceTime(1);
6509 
6510     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6511     addrCallback = sAddrCallbacks.GetHead();
6512     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6513     VerifyOrQuit(addrCallback->Matches(addrs, 4));
6514     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6515 
6516     VerifyOrQuit(sDnsMessages.IsEmpty());
6517 
6518     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6519     Log("Start same resolver again and check the returned error.");
6520 
6521     sAddrCallbacks.Clear();
6522 
6523     VerifyOrQuit(mdns->StartIp6AddressResolver(resolver2) == kErrorAlready);
6524 
6525     AdvanceTime(5000);
6526 
6527     VerifyOrQuit(sAddrCallbacks.IsEmpty());
6528     sDnsMessages.Clear();
6529 
6530     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6531     Log("Check query is sent at 80 percentage of TTL and then respond to it.");
6532 
6533     SendHostAddrResponse("myhost.local.", addrs, 4, /* aCachFlush */ true, kInAnswerSection);
6534 
6535     // First query should be sent at 80-82% of TTL of 120 second (96.0-98.4 sec).
6536     // We wait for 100 second. Note that 5 seconds already passed in the
6537     // previous step.
6538 
6539     AdvanceTime(96 * 1000 - 1);
6540 
6541     VerifyOrQuit(sDnsMessages.IsEmpty());
6542 
6543     AdvanceTime(4 * 1000 + 1);
6544 
6545     VerifyOrQuit(!sDnsMessages.IsEmpty());
6546     dnsMsg = sDnsMessages.GetHead();
6547     dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
6548     dnsMsg->ValidateAsQueryFor(resolver);
6549     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
6550 
6551     sDnsMessages.Clear();
6552     VerifyOrQuit(sAddrCallbacks.IsEmpty());
6553 
6554     AdvanceTime(10);
6555 
6556     SendHostAddrResponse("myhost.local.", addrs, 4, /* aCachFlush */ true, kInAnswerSection);
6557 
6558     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6559     Log("Check queries are sent at 80, 85, 90, 95 percentages of TTL.");
6560 
6561     for (uint8_t queryCount = 0; queryCount < kNumRefreshQueries; queryCount++)
6562     {
6563         if (queryCount == 0)
6564         {
6565             // First query is expected in 80-82% of TTL, so
6566             // 80% of 120 = 96.0, 82% of 120 = 98.4
6567 
6568             AdvanceTime(96 * 1000 - 1);
6569         }
6570         else
6571         {
6572             // Next query should happen within 3%-5% of TTL
6573             // from previous query. We wait 3% of TTL here.
6574             AdvanceTime(3600 - 1);
6575         }
6576 
6577         VerifyOrQuit(sDnsMessages.IsEmpty());
6578 
6579         // Wait for 2% of TTL of 120 which is 2.4 sec.
6580 
6581         AdvanceTime(2400 + 1);
6582 
6583         VerifyOrQuit(!sDnsMessages.IsEmpty());
6584         dnsMsg = sDnsMessages.GetHead();
6585         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
6586         dnsMsg->ValidateAsQueryFor(resolver);
6587         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
6588 
6589         sDnsMessages.Clear();
6590         VerifyOrQuit(sAddrCallbacks.IsEmpty());
6591     }
6592 
6593     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6594     Log("Check TTL timeout of first address (TTL 120) and callback result.");
6595 
6596     AdvanceTime(6 * 1000);
6597 
6598     addrCallback = sAddrCallbacks.GetHead();
6599 
6600     for (uint8_t iter = 0; iter < 2; iter++)
6601     {
6602         VerifyOrQuit(addrCallback != nullptr);
6603         VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6604         VerifyOrQuit(addrCallback->Matches(&addrs[1], 3));
6605         addrCallback = addrCallback->GetNext();
6606     }
6607 
6608     VerifyOrQuit(addrCallback == nullptr);
6609 
6610     VerifyOrQuit(sDnsMessages.IsEmpty());
6611 
6612     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6613     Log("Check TTL timeout of next address (TTL 800) and callback result.");
6614 
6615     sAddrCallbacks.Clear();
6616 
6617     AdvanceTime((800 - 120) * 1000);
6618 
6619     addrCallback = sAddrCallbacks.GetHead();
6620 
6621     for (uint8_t iter = 0; iter < 2; iter++)
6622     {
6623         VerifyOrQuit(addrCallback != nullptr);
6624         VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6625         VerifyOrQuit(addrCallback->Matches(&addrs[2], 2));
6626         addrCallback = addrCallback->GetNext();
6627     }
6628 
6629     VerifyOrQuit(addrCallback == nullptr);
6630 
6631     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6632 
6633     sAddrCallbacks.Clear();
6634     sDnsMessages.Clear();
6635 
6636     AdvanceTime(200 * 1000);
6637 
6638     VerifyOrQuit(sAddrCallbacks.IsEmpty());
6639     VerifyOrQuit(sDnsMessages.IsEmpty());
6640 
6641     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6642     Log("Stop the second resolver");
6643 
6644     sAddrCallbacks.Clear();
6645 
6646     SuccessOrQuit(mdns->StopIp6AddressResolver(resolver2));
6647 
6648     AdvanceTime(100 * 1000);
6649 
6650     VerifyOrQuit(sAddrCallbacks.IsEmpty());
6651     VerifyOrQuit(sDnsMessages.IsEmpty());
6652 
6653     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6654     Log("Send a new response and make sure result callback is invoked");
6655 
6656     sAddrCallbacks.Clear();
6657 
6658     SendHostAddrResponse("myhost.local.", addrs, 1, /* aCachFlush */ true, kInAnswerSection);
6659 
6660     AdvanceTime(1);
6661 
6662     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6663     addrCallback = sAddrCallbacks.GetHead();
6664     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6665     VerifyOrQuit(addrCallback->Matches(addrs, 1));
6666     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6667 
6668     VerifyOrQuit(sDnsMessages.IsEmpty());
6669 
6670     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6671     Log("Stop the resolver. There is no active resolver. Ensure no queries are sent");
6672 
6673     sAddrCallbacks.Clear();
6674 
6675     SuccessOrQuit(mdns->StopIp6AddressResolver(resolver));
6676 
6677     AdvanceTime(20 * 1000);
6678 
6679     VerifyOrQuit(sAddrCallbacks.IsEmpty());
6680     VerifyOrQuit(sDnsMessages.IsEmpty());
6681 
6682     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6683     Log("Restart the resolver with more than half of TTL remaining.");
6684     Log("Ensure cached entry is reported in the result callback and no queries are sent.");
6685 
6686     SuccessOrQuit(mdns->StartIp6AddressResolver(resolver));
6687 
6688     AdvanceTime(1);
6689 
6690     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6691     addrCallback = sAddrCallbacks.GetHead();
6692     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6693     VerifyOrQuit(addrCallback->Matches(addrs, 1));
6694     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6695 
6696     VerifyOrQuit(sDnsMessages.IsEmpty());
6697 
6698     AdvanceTime(20 * 1000);
6699 
6700     VerifyOrQuit(sDnsMessages.IsEmpty());
6701 
6702     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6703     Log("Stop and start the resolver again after less than half TTL remaining.");
6704     Log("Ensure cached entry is still reported in the result callback but queries should be sent");
6705 
6706     sAddrCallbacks.Clear();
6707 
6708     SuccessOrQuit(mdns->StopIp6AddressResolver(resolver));
6709 
6710     AdvanceTime(25 * 1000);
6711 
6712     SuccessOrQuit(mdns->StartIp6AddressResolver(resolver));
6713 
6714     AdvanceTime(1);
6715 
6716     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6717     addrCallback = sAddrCallbacks.GetHead();
6718     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6719     VerifyOrQuit(addrCallback->Matches(addrs, 1));
6720     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6721 
6722     sAddrCallbacks.Clear();
6723 
6724     AdvanceTime(15 * 1000);
6725 
6726     dnsMsg = sDnsMessages.GetHead();
6727 
6728     for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; queryCount++)
6729     {
6730         VerifyOrQuit(dnsMsg != nullptr);
6731         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
6732         dnsMsg->ValidateAsQueryFor(resolver);
6733         dnsMsg = dnsMsg->GetNext();
6734     }
6735 
6736     VerifyOrQuit(dnsMsg == nullptr);
6737 
6738     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6739 
6740     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
6741     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
6742 
6743     Log("End of test");
6744 
6745     testFreeInstance(sInstance);
6746 }
6747 
TestPassiveCache(void)6748 void TestPassiveCache(void)
6749 {
6750     static const char *const kSubTypes[] = {"_sub1", "_xyzw"};
6751 
6752     Core                 *mdns = InitTest();
6753     Core::Browser         browser;
6754     Core::SrvResolver     srvResolver;
6755     Core::TxtResolver     txtResolver;
6756     Core::AddressResolver addrResolver;
6757     Core::Host            host1;
6758     Core::Host            host2;
6759     Core::Service         service1;
6760     Core::Service         service2;
6761     Core::Service         service3;
6762     Ip6::Address          host1Addresses[3];
6763     Ip6::Address          host2Addresses[2];
6764     AddrAndTtl            host1AddrTtls[3];
6765     AddrAndTtl            host2AddrTtls[2];
6766     const DnsMessage     *dnsMsg;
6767     BrowseCallback       *browseCallback;
6768     SrvCallback          *srvCallback;
6769     TxtCallback          *txtCallback;
6770     AddrCallback         *addrCallback;
6771     uint16_t              heapAllocations;
6772 
6773     Log("-------------------------------------------------------------------------------------------");
6774     Log("TestPassiveCache");
6775 
6776     AdvanceTime(1);
6777 
6778     heapAllocations = sHeapAllocatedPtrs.GetLength();
6779     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
6780 
6781     SuccessOrQuit(host1Addresses[0].FromString("fd00::1:aaaa"));
6782     SuccessOrQuit(host1Addresses[1].FromString("fd00::1:bbbb"));
6783     SuccessOrQuit(host1Addresses[2].FromString("fd00::1:cccc"));
6784     host1.mHostName        = "host1";
6785     host1.mAddresses       = host1Addresses;
6786     host1.mAddressesLength = 3;
6787     host1.mTtl             = 1500;
6788 
6789     host1AddrTtls[0].mAddress = host1Addresses[0];
6790     host1AddrTtls[1].mAddress = host1Addresses[1];
6791     host1AddrTtls[2].mAddress = host1Addresses[2];
6792     host1AddrTtls[0].mTtl     = host1.mTtl;
6793     host1AddrTtls[1].mTtl     = host1.mTtl;
6794     host1AddrTtls[2].mTtl     = host1.mTtl;
6795 
6796     SuccessOrQuit(host2Addresses[0].FromString("fd00::2:eeee"));
6797     SuccessOrQuit(host2Addresses[1].FromString("fd00::2:ffff"));
6798     host2.mHostName        = "host2";
6799     host2.mAddresses       = host2Addresses;
6800     host2.mAddressesLength = 2;
6801     host2.mTtl             = 1500;
6802 
6803     host2AddrTtls[0].mAddress = host2Addresses[0];
6804     host2AddrTtls[1].mAddress = host2Addresses[1];
6805     host2AddrTtls[0].mTtl     = host2.mTtl;
6806     host2AddrTtls[1].mTtl     = host2.mTtl;
6807 
6808     service1.mHostName            = host1.mHostName;
6809     service1.mServiceInstance     = "srv1";
6810     service1.mServiceType         = "_srv._udp";
6811     service1.mSubTypeLabels       = kSubTypes;
6812     service1.mSubTypeLabelsLength = 2;
6813     service1.mTxtData             = kTxtData1;
6814     service1.mTxtDataLength       = sizeof(kTxtData1);
6815     service1.mPort                = 1111;
6816     service1.mPriority            = 0;
6817     service1.mWeight              = 0;
6818     service1.mTtl                 = 1500;
6819 
6820     service2.mHostName            = host1.mHostName;
6821     service2.mServiceInstance     = "srv2";
6822     service2.mServiceType         = "_tst._tcp";
6823     service2.mSubTypeLabels       = nullptr;
6824     service2.mSubTypeLabelsLength = 0;
6825     service2.mTxtData             = nullptr;
6826     service2.mTxtDataLength       = 0;
6827     service2.mPort                = 2222;
6828     service2.mPriority            = 2;
6829     service2.mWeight              = 2;
6830     service2.mTtl                 = 1500;
6831 
6832     service3.mHostName            = host2.mHostName;
6833     service3.mServiceInstance     = "srv3";
6834     service3.mServiceType         = "_srv._udp";
6835     service3.mSubTypeLabels       = kSubTypes;
6836     service3.mSubTypeLabelsLength = 1;
6837     service3.mTxtData             = kTxtData2;
6838     service3.mTxtDataLength       = sizeof(kTxtData2);
6839     service3.mPort                = 3333;
6840     service3.mPriority            = 3;
6841     service3.mWeight              = 3;
6842     service3.mTtl                 = 1500;
6843 
6844     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6845     Log("Register 2 hosts and 3 services");
6846 
6847     SuccessOrQuit(mdns->RegisterHost(host1, 0, HandleSuccessCallback));
6848     SuccessOrQuit(mdns->RegisterHost(host2, 1, HandleSuccessCallback));
6849     SuccessOrQuit(mdns->RegisterService(service1, 2, HandleSuccessCallback));
6850     SuccessOrQuit(mdns->RegisterService(service2, 3, HandleSuccessCallback));
6851     SuccessOrQuit(mdns->RegisterService(service3, 4, HandleSuccessCallback));
6852 
6853     AdvanceTime(10 * 1000);
6854 
6855     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6856     Log("Start a browser for `_srv._udp`, validate callback result");
6857 
6858     browser.mServiceType  = "_srv._udp";
6859     browser.mSubTypeLabel = nullptr;
6860     browser.mInfraIfIndex = kInfraIfIndex;
6861     browser.mCallback     = HandleBrowseResult;
6862 
6863     sBrowseCallbacks.Clear();
6864 
6865     SuccessOrQuit(mdns->StartBrowser(browser));
6866 
6867     AdvanceTime(350);
6868 
6869     browseCallback = sBrowseCallbacks.GetHead();
6870 
6871     for (uint8_t iter = 0; iter < 2; iter++)
6872     {
6873         VerifyOrQuit(browseCallback != nullptr);
6874 
6875         VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
6876         VerifyOrQuit(!browseCallback->mIsSubType);
6877         VerifyOrQuit(browseCallback->mServiceInstance.Matches("srv1") ||
6878                      browseCallback->mServiceInstance.Matches("srv3"));
6879         VerifyOrQuit(browseCallback->mTtl == 1500);
6880 
6881         browseCallback = browseCallback->GetNext();
6882     }
6883 
6884     VerifyOrQuit(browseCallback == nullptr);
6885 
6886     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6887     Log("Start SRV and TXT resolvers for the srv1 and for its host name.");
6888     Log("Ensure all results are immediately provided from cache.");
6889 
6890     srvResolver.mServiceInstance = "srv1";
6891     srvResolver.mServiceType     = "_srv._udp";
6892     srvResolver.mInfraIfIndex    = kInfraIfIndex;
6893     srvResolver.mCallback        = HandleSrvResult;
6894 
6895     txtResolver.mServiceInstance = "srv1";
6896     txtResolver.mServiceType     = "_srv._udp";
6897     txtResolver.mInfraIfIndex    = kInfraIfIndex;
6898     txtResolver.mCallback        = HandleTxtResult;
6899 
6900     addrResolver.mHostName     = "host1";
6901     addrResolver.mInfraIfIndex = kInfraIfIndex;
6902     addrResolver.mCallback     = HandleAddrResult;
6903 
6904     sSrvCallbacks.Clear();
6905     sTxtCallbacks.Clear();
6906     sAddrCallbacks.Clear();
6907     sDnsMessages.Clear();
6908 
6909     SuccessOrQuit(mdns->StartSrvResolver(srvResolver));
6910     SuccessOrQuit(mdns->StartTxtResolver(txtResolver));
6911     SuccessOrQuit(mdns->StartIp6AddressResolver(addrResolver));
6912 
6913     AdvanceTime(1);
6914 
6915     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
6916     srvCallback = sSrvCallbacks.GetHead();
6917     VerifyOrQuit(srvCallback->mServiceInstance.Matches("srv1"));
6918     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
6919     VerifyOrQuit(srvCallback->mHostName.Matches("host1"));
6920     VerifyOrQuit(srvCallback->mPort == 1111);
6921     VerifyOrQuit(srvCallback->mPriority == 0);
6922     VerifyOrQuit(srvCallback->mWeight == 0);
6923     VerifyOrQuit(srvCallback->mTtl == 1500);
6924     VerifyOrQuit(srvCallback->GetNext() == nullptr);
6925 
6926     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
6927     txtCallback = sTxtCallbacks.GetHead();
6928     VerifyOrQuit(txtCallback->mServiceInstance.Matches("srv1"));
6929     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
6930     VerifyOrQuit(txtCallback->Matches(kTxtData1));
6931     VerifyOrQuit(txtCallback->mTtl == 1500);
6932     VerifyOrQuit(txtCallback->GetNext() == nullptr);
6933 
6934     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6935     addrCallback = sAddrCallbacks.GetHead();
6936     VerifyOrQuit(addrCallback->mHostName.Matches("host1"));
6937     VerifyOrQuit(addrCallback->Matches(host1AddrTtls, 3));
6938     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6939 
6940     AdvanceTime(400);
6941 
6942     VerifyOrQuit(sDnsMessages.IsEmpty());
6943 
6944     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6945     Log("Start a browser for sub-type service, validate callback result");
6946 
6947     browser.mServiceType  = "_srv._udp";
6948     browser.mSubTypeLabel = "_xyzw";
6949     browser.mInfraIfIndex = kInfraIfIndex;
6950     browser.mCallback     = HandleBrowseResult;
6951 
6952     sBrowseCallbacks.Clear();
6953 
6954     SuccessOrQuit(mdns->StartBrowser(browser));
6955 
6956     AdvanceTime(350);
6957 
6958     browseCallback = sBrowseCallbacks.GetHead();
6959     VerifyOrQuit(browseCallback != nullptr);
6960 
6961     VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
6962     VerifyOrQuit(browseCallback->mIsSubType);
6963     VerifyOrQuit(browseCallback->mSubTypeLabel.Matches("_xyzw"));
6964     VerifyOrQuit(browseCallback->mServiceInstance.Matches("srv1"));
6965     VerifyOrQuit(browseCallback->mTtl == 1500);
6966     VerifyOrQuit(browseCallback->GetNext() == nullptr);
6967 
6968     AdvanceTime(5 * 1000);
6969 
6970     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6971     Log("Start SRV and TXT resolvers for `srv2._tst._tcp` service and validate callback result");
6972 
6973     srvResolver.mServiceInstance = "srv2";
6974     srvResolver.mServiceType     = "_tst._tcp";
6975     srvResolver.mInfraIfIndex    = kInfraIfIndex;
6976     srvResolver.mCallback        = HandleSrvResult;
6977 
6978     txtResolver.mServiceInstance = "srv2";
6979     txtResolver.mServiceType     = "_tst._tcp";
6980     txtResolver.mInfraIfIndex    = kInfraIfIndex;
6981     txtResolver.mCallback        = HandleTxtResult;
6982 
6983     sSrvCallbacks.Clear();
6984     sTxtCallbacks.Clear();
6985 
6986     SuccessOrQuit(mdns->StartSrvResolver(srvResolver));
6987     SuccessOrQuit(mdns->StartTxtResolver(txtResolver));
6988 
6989     AdvanceTime(350);
6990 
6991     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
6992     srvCallback = sSrvCallbacks.GetHead();
6993     VerifyOrQuit(srvCallback->mServiceInstance.Matches("srv2"));
6994     VerifyOrQuit(srvCallback->mServiceType.Matches("_tst._tcp"));
6995     VerifyOrQuit(srvCallback->mHostName.Matches("host1"));
6996     VerifyOrQuit(srvCallback->mPort == 2222);
6997     VerifyOrQuit(srvCallback->mPriority == 2);
6998     VerifyOrQuit(srvCallback->mWeight == 2);
6999     VerifyOrQuit(srvCallback->mTtl == 1500);
7000     VerifyOrQuit(srvCallback->GetNext() == nullptr);
7001 
7002     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
7003     txtCallback = sTxtCallbacks.GetHead();
7004     VerifyOrQuit(txtCallback->mServiceInstance.Matches("srv2"));
7005     VerifyOrQuit(txtCallback->mServiceType.Matches("_tst._tcp"));
7006     VerifyOrQuit(txtCallback->Matches(kEmptyTxtData));
7007     VerifyOrQuit(txtCallback->mTtl == 1500);
7008     VerifyOrQuit(txtCallback->GetNext() == nullptr);
7009 
7010     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7011     Log("Unregister `srv2._tst._tcp` and validate callback results");
7012 
7013     sSrvCallbacks.Clear();
7014     sTxtCallbacks.Clear();
7015 
7016     SuccessOrQuit(mdns->UnregisterService(service2));
7017 
7018     AdvanceTime(350);
7019 
7020     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
7021     srvCallback = sSrvCallbacks.GetHead();
7022     VerifyOrQuit(srvCallback->mServiceInstance.Matches("srv2"));
7023     VerifyOrQuit(srvCallback->mServiceType.Matches("_tst._tcp"));
7024     VerifyOrQuit(srvCallback->mTtl == 0);
7025     VerifyOrQuit(srvCallback->GetNext() == nullptr);
7026 
7027     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
7028     txtCallback = sTxtCallbacks.GetHead();
7029     VerifyOrQuit(txtCallback->mServiceInstance.Matches("srv2"));
7030     VerifyOrQuit(txtCallback->mServiceType.Matches("_tst._tcp"));
7031     VerifyOrQuit(txtCallback->mTtl == 0);
7032     VerifyOrQuit(txtCallback->GetNext() == nullptr);
7033 
7034     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7035     Log("Start an SRV resolver for `srv3._srv._udp` service and validate callback result");
7036 
7037     srvResolver.mServiceInstance = "srv3";
7038     srvResolver.mServiceType     = "_srv._udp";
7039     srvResolver.mInfraIfIndex    = kInfraIfIndex;
7040     srvResolver.mCallback        = HandleSrvResult;
7041 
7042     sSrvCallbacks.Clear();
7043 
7044     SuccessOrQuit(mdns->StartSrvResolver(srvResolver));
7045 
7046     AdvanceTime(350);
7047 
7048     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
7049     srvCallback = sSrvCallbacks.GetHead();
7050     VerifyOrQuit(srvCallback->mServiceInstance.Matches("srv3"));
7051     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
7052     VerifyOrQuit(srvCallback->mHostName.Matches("host2"));
7053     VerifyOrQuit(srvCallback->mPort == 3333);
7054     VerifyOrQuit(srvCallback->mPriority == 3);
7055     VerifyOrQuit(srvCallback->mWeight == 3);
7056     VerifyOrQuit(srvCallback->mTtl == 1500);
7057     VerifyOrQuit(srvCallback->GetNext() == nullptr);
7058 
7059     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7060     Log("Start an address resolver for host2 and validate result is immediately reported from cache");
7061 
7062     addrResolver.mHostName     = "host2";
7063     addrResolver.mInfraIfIndex = kInfraIfIndex;
7064     addrResolver.mCallback     = HandleAddrResult;
7065 
7066     sAddrCallbacks.Clear();
7067     SuccessOrQuit(mdns->StartIp6AddressResolver(addrResolver));
7068 
7069     AdvanceTime(1);
7070 
7071     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
7072     addrCallback = sAddrCallbacks.GetHead();
7073     VerifyOrQuit(addrCallback->mHostName.Matches("host2"));
7074     VerifyOrQuit(addrCallback->Matches(host2AddrTtls, 2));
7075     VerifyOrQuit(addrCallback->GetNext() == nullptr);
7076 
7077     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7078 
7079     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
7080     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
7081 
7082     Log("End of test");
7083 
7084     testFreeInstance(sInstance);
7085 }
7086 
TestLegacyUnicastResponse(void)7087 void TestLegacyUnicastResponse(void)
7088 {
7089     Core             *mdns = InitTest();
7090     Core::Host        host;
7091     Core::Service     service;
7092     const DnsMessage *dnsMsg;
7093     uint16_t          heapAllocations;
7094     DnsNameString     fullServiceName;
7095     DnsNameString     fullServiceType;
7096     DnsNameString     hostFullName;
7097     Ip6::Address      hostAddresses[2];
7098 
7099     Log("-------------------------------------------------------------------------------------------");
7100     Log("TestLegacyUnicastResponse");
7101 
7102     AdvanceTime(1);
7103 
7104     heapAllocations = sHeapAllocatedPtrs.GetLength();
7105     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
7106 
7107     SuccessOrQuit(hostAddresses[0].FromString("fd00::1:aaaa"));
7108     SuccessOrQuit(hostAddresses[1].FromString("fd00::1:bbbb"));
7109     host.mHostName        = "host";
7110     host.mAddresses       = hostAddresses;
7111     host.mAddressesLength = 2;
7112     host.mTtl             = 1500;
7113     hostFullName.Append("%s.local.", host.mHostName);
7114 
7115     service.mHostName            = host.mHostName;
7116     service.mServiceInstance     = "myservice";
7117     service.mServiceType         = "_srv._udp";
7118     service.mSubTypeLabels       = nullptr;
7119     service.mSubTypeLabelsLength = 0;
7120     service.mTxtData             = kTxtData1;
7121     service.mTxtDataLength       = sizeof(kTxtData1);
7122     service.mPort                = 1234;
7123     service.mPriority            = 1;
7124     service.mWeight              = 2;
7125     service.mTtl                 = 1000;
7126 
7127     fullServiceName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
7128     fullServiceType.Append("%s.local.", service.mServiceType);
7129 
7130     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7131 
7132     sDnsMessages.Clear();
7133 
7134     for (RegCallback &regCallbck : sRegCallbacks)
7135     {
7136         regCallbck.Reset();
7137     }
7138 
7139     SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
7140     SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
7141 
7142     AdvanceTime(10 * 1000);
7143 
7144     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7145     Log("Send a query with two questions (SRV for service1 and AAAA for host). Validate that no response is sent");
7146 
7147     AdvanceTime(2000);
7148 
7149     sDnsMessages.Clear();
7150     SendQueryForTwo(fullServiceName.AsCString(), ResourceRecord::kTypeSrv, hostFullName.AsCString(),
7151                     ResourceRecord::kTypeAaaa, /* aIsLegacyUnicast */ true);
7152 
7153     AdvanceTime(200);
7154 
7155     dnsMsg = sDnsMessages.GetHead();
7156     VerifyOrQuit(dnsMsg == nullptr);
7157 
7158     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7159     Log("Send a query for SRV record and validate the response");
7160 
7161     AdvanceTime(2000);
7162 
7163     sDnsMessages.Clear();
7164     SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeSrv, ResourceRecord::kClassInternet,
7165               /* aTruncated */ false,
7166               /* aLegacyUnicastQuery */ true);
7167 
7168     AdvanceTime(1000);
7169 
7170     dnsMsg = sDnsMessages.GetHead();
7171     VerifyOrQuit(dnsMsg != nullptr);
7172     dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 3);
7173     dnsMsg->Validate(service, kInAnswerSection, kCheckSrv);
7174     dnsMsg->Validate(host, kInAdditionalSection);
7175 
7176     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7177     Log("Send a query for TXT record and validate the response");
7178 
7179     AdvanceTime(2000);
7180 
7181     sDnsMessages.Clear();
7182     SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeTxt, ResourceRecord::kClassInternet,
7183               /* aTruncated */ false,
7184               /* aLegacyUnicastQuery */ true);
7185 
7186     AdvanceTime(1000);
7187 
7188     dnsMsg = sDnsMessages.GetHead();
7189     VerifyOrQuit(dnsMsg != nullptr);
7190     dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
7191     dnsMsg->Validate(service, kInAnswerSection, kCheckTxt);
7192 
7193     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7194     Log("Send a query for ANY record and validate the response");
7195 
7196     AdvanceTime(2000);
7197 
7198     sDnsMessages.Clear();
7199     SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeAny, ResourceRecord::kClassInternet,
7200               /* aTruncated */ false,
7201               /* aLegacyUnicastQuery */ true);
7202 
7203     AdvanceTime(1000);
7204 
7205     dnsMsg = sDnsMessages.GetHead();
7206     VerifyOrQuit(dnsMsg != nullptr);
7207     dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 3);
7208     dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt);
7209     dnsMsg->Validate(host, kInAdditionalSection);
7210 
7211     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7212     Log("Send a query for PTR record for service type and validate the response");
7213 
7214     AdvanceTime(2000);
7215 
7216     sDnsMessages.Clear();
7217     SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
7218               /* aTruncated */ false,
7219               /* aLegacyUnicastQuery */ true);
7220 
7221     AdvanceTime(1000);
7222 
7223     dnsMsg = sDnsMessages.GetHead();
7224     VerifyOrQuit(dnsMsg != nullptr);
7225     dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 4);
7226     dnsMsg->Validate(service, kInAnswerSection, kCheckPtr);
7227     dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
7228     dnsMsg->Validate(host, kInAdditionalSection);
7229 
7230     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7231     Log("Send a query for non-existing record and validate the response with NSEC");
7232 
7233     AdvanceTime(2000);
7234 
7235     sDnsMessages.Clear();
7236     SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeA, ResourceRecord::kClassInternet, /* aTruncated */ false,
7237               /* aLegacyUnicastQuery */ true);
7238 
7239     AdvanceTime(1000);
7240 
7241     dnsMsg = sDnsMessages.GetHead();
7242     VerifyOrQuit(dnsMsg != nullptr);
7243     dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 1);
7244     VerifyOrQuit(dnsMsg->mAdditionalRecords.ContainsNsec(hostFullName, ResourceRecord::kTypeAaaa));
7245 
7246     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7247 
7248     sDnsMessages.Clear();
7249 
7250     SuccessOrQuit(mdns->UnregisterHost(host));
7251 
7252     AdvanceTime(15000);
7253 
7254     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
7255     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
7256 
7257     Log("End of test");
7258 
7259     testFreeInstance(sInstance);
7260 }
7261 
7262 } // namespace Multicast
7263 } // namespace Dns
7264 } // namespace ot
7265 
7266 #endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
7267 
main(void)7268 int main(void)
7269 {
7270 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
7271     ot::Dns::Multicast::TestHostReg();
7272     ot::Dns::Multicast::TestKeyReg();
7273     ot::Dns::Multicast::TestServiceReg();
7274     ot::Dns::Multicast::TestUnregisterBeforeProbeFinished();
7275     ot::Dns::Multicast::TestServiceSubTypeReg();
7276     ot::Dns::Multicast::TestHostOrServiceAndKeyReg();
7277     ot::Dns::Multicast::TestQuery();
7278     ot::Dns::Multicast::TestMultiPacket();
7279     ot::Dns::Multicast::TestResponseAggregation();
7280     ot::Dns::Multicast::TestQuestionUnicastDisallowed();
7281     ot::Dns::Multicast::TestTxMessageSizeLimit();
7282     ot::Dns::Multicast::TestHostConflict();
7283     ot::Dns::Multicast::TestServiceConflict();
7284 
7285     ot::Dns::Multicast::TestBrowser();
7286     ot::Dns::Multicast::TestSrvResolver();
7287     ot::Dns::Multicast::TestTxtResolver();
7288     ot::Dns::Multicast::TestIp6AddrResolver();
7289     ot::Dns::Multicast::TestPassiveCache();
7290     ot::Dns::Multicast::TestLegacyUnicastResponse();
7291 
7292     printf("All tests passed\n");
7293 #else
7294     printf("mDNS feature is not enabled\n");
7295 #endif
7296 
7297     return 0;
7298 }
7299