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 
4051 //---------------------------------------------------------------------------------------------------------------------
4052 
TestQuestionUnicastDisallowed(void)4053 void TestQuestionUnicastDisallowed(void)
4054 {
4055     Core             *mdns = InitTest();
4056     Core::Host        host;
4057     Ip6::Address      hostAddresses[1];
4058     const DnsMessage *dnsMsg;
4059     uint16_t          heapAllocations;
4060     DnsNameString     hostFullName;
4061 
4062     Log("-------------------------------------------------------------------------------------------");
4063     Log("TestQuestionUnicastDisallowed");
4064 
4065     AdvanceTime(1);
4066 
4067     heapAllocations = sHeapAllocatedPtrs.GetLength();
4068     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
4069 
4070     SuccessOrQuit(hostAddresses[0].FromString("fd00::1234"));
4071 
4072     host.mHostName        = "myhost";
4073     host.mAddresses       = hostAddresses;
4074     host.mAddressesLength = 1;
4075     host.mTtl             = 1500;
4076 
4077     mdns->SetQuestionUnicastAllowed(false);
4078     VerifyOrQuit(!mdns->IsQuestionUnicastAllowed());
4079 
4080     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4081     Log("Register a `HostEntry`, check probes and announcements");
4082 
4083     sDnsMessages.Clear();
4084 
4085     sRegCallbacks[0].Reset();
4086     SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
4087 
4088     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
4089     {
4090         sDnsMessages.Clear();
4091 
4092         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4093         AdvanceTime(250);
4094 
4095         VerifyOrQuit(!sDnsMessages.IsEmpty());
4096         dnsMsg = sDnsMessages.GetHead();
4097         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 1, /* Addnl */ 0);
4098         dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ false);
4099         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4100     }
4101 
4102     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
4103     {
4104         sDnsMessages.Clear();
4105 
4106         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
4107         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4108 
4109         VerifyOrQuit(!sDnsMessages.IsEmpty());
4110         dnsMsg = sDnsMessages.GetHead();
4111         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
4112         dnsMsg->Validate(host, kInAnswerSection);
4113         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4114     }
4115 
4116     sDnsMessages.Clear();
4117     AdvanceTime(15000);
4118     VerifyOrQuit(sDnsMessages.IsEmpty());
4119 
4120     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
4121     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
4122 
4123     Log("End of test");
4124 
4125     testFreeInstance(sInstance);
4126 }
4127 
4128 //---------------------------------------------------------------------------------------------------------------------
4129 
TestTxMessageSizeLimit(void)4130 void TestTxMessageSizeLimit(void)
4131 {
4132     Core             *mdns = InitTest();
4133     Core::Host        host;
4134     Core::Service     service;
4135     Core::Key         hostKey;
4136     Core::Key         serviceKey;
4137     Ip6::Address      hostAddresses[3];
4138     uint8_t           keyData[300];
4139     const DnsMessage *dnsMsg;
4140     uint16_t          heapAllocations;
4141     DnsNameString     hostFullName;
4142     DnsNameString     serviceFullName;
4143 
4144     memset(keyData, 1, sizeof(keyData));
4145 
4146     Log("-------------------------------------------------------------------------------------------");
4147     Log("TestTxMessageSizeLimit");
4148 
4149     AdvanceTime(1);
4150 
4151     heapAllocations = sHeapAllocatedPtrs.GetLength();
4152     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
4153 
4154     SuccessOrQuit(hostAddresses[0].FromString("fd00::1:aaaa"));
4155     SuccessOrQuit(hostAddresses[1].FromString("fd00::1:bbbb"));
4156     SuccessOrQuit(hostAddresses[2].FromString("fd00::1:cccc"));
4157     host.mHostName        = "myhost";
4158     host.mAddresses       = hostAddresses;
4159     host.mAddressesLength = 3;
4160     host.mTtl             = 1500;
4161     hostFullName.Append("%s.local.", host.mHostName);
4162 
4163     service.mHostName            = host.mHostName;
4164     service.mServiceInstance     = "mysrv";
4165     service.mServiceType         = "_srv._udp";
4166     service.mSubTypeLabels       = nullptr;
4167     service.mSubTypeLabelsLength = 0;
4168     service.mTxtData             = kTxtData1;
4169     service.mTxtDataLength       = sizeof(kTxtData1);
4170     service.mPort                = 1111;
4171     service.mPriority            = 0;
4172     service.mWeight              = 0;
4173     service.mTtl                 = 1500;
4174     serviceFullName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
4175 
4176     hostKey.mName          = host.mHostName;
4177     hostKey.mServiceType   = nullptr;
4178     hostKey.mKeyData       = keyData;
4179     hostKey.mKeyDataLength = 300;
4180     hostKey.mTtl           = 8000;
4181 
4182     serviceKey.mName          = service.mServiceInstance;
4183     serviceKey.mServiceType   = service.mServiceType;
4184     serviceKey.mKeyData       = keyData;
4185     serviceKey.mKeyDataLength = 300;
4186     serviceKey.mTtl           = 8000;
4187 
4188     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4189     Log("Set `MaxMessageSize` to 340 and use large key record data to trigger size limit behavior");
4190 
4191     mdns->SetMaxMessageSize(340);
4192 
4193     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4194     Log("Register host and service and keys for each");
4195 
4196     sDnsMessages.Clear();
4197 
4198     for (RegCallback &regCallbck : sRegCallbacks)
4199     {
4200         regCallbck.Reset();
4201     }
4202 
4203     SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
4204     SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
4205     SuccessOrQuit(mdns->RegisterKey(hostKey, 2, HandleSuccessCallback));
4206     SuccessOrQuit(mdns->RegisterKey(serviceKey, 3, HandleSuccessCallback));
4207 
4208     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4209     Log("Validate probes for all entries");
4210     Log("Probes for host and service should be broken into separate message due to size limit");
4211 
4212     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
4213     {
4214         sDnsMessages.Clear();
4215         AdvanceTime(250);
4216 
4217         VerifyOrQuit(!sDnsMessages.IsEmpty());
4218         dnsMsg = sDnsMessages.GetHead();
4219 
4220         for (uint16_t index = 0; index < 4; index++)
4221         {
4222             VerifyOrQuit(!sRegCallbacks[index].mWasCalled);
4223         }
4224 
4225         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 4, /* Addnl */ 0);
4226         dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ (probeCount == 0));
4227         dnsMsg->ValidateAsProbeFor(hostKey, /* aUnicastRequest */ (probeCount == 0));
4228 
4229         dnsMsg = dnsMsg->GetNext();
4230         VerifyOrQuit(dnsMsg != nullptr);
4231 
4232         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 3, /* Addnl */ 0);
4233         dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ (probeCount == 0));
4234         dnsMsg->ValidateAsProbeFor(serviceKey, /* aUnicastRequest */ (probeCount == 0));
4235 
4236         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4237     }
4238 
4239     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4240     Log("Validate announcements for all entries");
4241     Log("Announces should also be broken into separate message due to size limit");
4242 
4243     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
4244     {
4245         sDnsMessages.Clear();
4246 
4247         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
4248 
4249         for (uint16_t index = 0; index < 4; index++)
4250         {
4251             VerifyOrQuit(sRegCallbacks[index].mWasCalled);
4252         }
4253 
4254         VerifyOrQuit(!sDnsMessages.IsEmpty());
4255         dnsMsg = sDnsMessages.GetHead();
4256 
4257         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
4258         dnsMsg->Validate(host, kInAnswerSection);
4259         dnsMsg->Validate(hostKey, kInAnswerSection);
4260 
4261         dnsMsg = dnsMsg->GetNext();
4262         VerifyOrQuit(dnsMsg != nullptr);
4263 
4264         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 4);
4265         dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr);
4266         dnsMsg->Validate(serviceKey, kInAnswerSection);
4267 
4268         dnsMsg = dnsMsg->GetNext();
4269         VerifyOrQuit(dnsMsg != nullptr);
4270 
4271         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
4272         dnsMsg->Validate(service, kInAnswerSection, kCheckServicesPtr);
4273 
4274         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4275     }
4276 
4277     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
4278     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
4279 
4280     Log("End of test");
4281 
4282     testFreeInstance(sInstance);
4283 }
4284 
4285 //---------------------------------------------------------------------------------------------------------------------
4286 
TestHostConflict(void)4287 void TestHostConflict(void)
4288 {
4289     Core             *mdns = InitTest();
4290     Core::Host        host;
4291     Ip6::Address      hostAddresses[2];
4292     const DnsMessage *dnsMsg;
4293     uint16_t          heapAllocations;
4294     DnsNameString     hostFullName;
4295 
4296     Log("-------------------------------------------------------------------------------------------");
4297     Log("TestHostConflict");
4298 
4299     AdvanceTime(1);
4300 
4301     heapAllocations = sHeapAllocatedPtrs.GetLength();
4302     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
4303 
4304     SuccessOrQuit(hostAddresses[0].FromString("fd00::1"));
4305     SuccessOrQuit(hostAddresses[1].FromString("fd00::2"));
4306 
4307     host.mHostName        = "myhost";
4308     host.mAddresses       = hostAddresses;
4309     host.mAddressesLength = 2;
4310     host.mTtl             = 1500;
4311 
4312     hostFullName.Append("%s.local.", host.mHostName);
4313 
4314     // Run the test twice, first run send response with record in Answer section,
4315     // section run in Additional Data section.
4316 
4317     sConflictCallback.Reset();
4318     mdns->SetConflictCallback(HandleConflict);
4319 
4320     for (uint8_t iter = 0; iter < 2; iter++)
4321     {
4322         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4323         Log("Register a `HostEntry`, wait for first probe");
4324 
4325         sDnsMessages.Clear();
4326 
4327         sRegCallbacks[0].Reset();
4328         SuccessOrQuit(mdns->RegisterHost(host, 0, HandleCallback));
4329 
4330         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4331         AdvanceTime(250);
4332 
4333         VerifyOrQuit(!sDnsMessages.IsEmpty());
4334         dnsMsg = sDnsMessages.GetHead();
4335         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
4336         dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ true);
4337         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4338 
4339         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4340         Log("Send a response claiming the name with record in %s section", (iter == 0) ? "answer" : "additional");
4341 
4342         SendResponseWithEmptyKey(hostFullName.AsCString(), (iter == 0) ? kInAnswerSection : kInAdditionalSection);
4343         AdvanceTime(1);
4344 
4345         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4346         VerifyOrQuit(sRegCallbacks[0].mError == kErrorDuplicated);
4347 
4348         VerifyOrQuit(!sConflictCallback.mWasCalled);
4349 
4350         sDnsMessages.Clear();
4351 
4352         SuccessOrQuit(mdns->UnregisterHost(host));
4353 
4354         AdvanceTime(15000);
4355         VerifyOrQuit(sDnsMessages.IsEmpty());
4356     }
4357 
4358     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4359     Log("Register a `HostEntry` and respond to probe to trigger conflict");
4360 
4361     sRegCallbacks[0].Reset();
4362     SuccessOrQuit(mdns->RegisterHost(host, 0, HandleCallback));
4363 
4364     VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4365 
4366     SendResponseWithEmptyKey(hostFullName.AsCString(), kInAnswerSection);
4367     AdvanceTime(1);
4368 
4369     VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4370     VerifyOrQuit(sRegCallbacks[0].mError == kErrorDuplicated);
4371     VerifyOrQuit(!sConflictCallback.mWasCalled);
4372 
4373     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4374     Log("Register the conflicted `HostEntry` again, and make sure no probes are sent");
4375 
4376     sRegCallbacks[1].Reset();
4377     sConflictCallback.Reset();
4378     sDnsMessages.Clear();
4379 
4380     SuccessOrQuit(mdns->RegisterHost(host, 1, HandleCallback));
4381     AdvanceTime(5000);
4382 
4383     VerifyOrQuit(sRegCallbacks[1].mWasCalled);
4384     VerifyOrQuit(sRegCallbacks[1].mError == kErrorDuplicated);
4385     VerifyOrQuit(!sConflictCallback.mWasCalled);
4386 
4387     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4388     Log("Unregister the conflicted host and register it again immediately, make sure we see probes");
4389 
4390     SuccessOrQuit(mdns->UnregisterHost(host));
4391 
4392     sConflictCallback.Reset();
4393     sRegCallbacks[0].Reset();
4394     SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
4395 
4396     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
4397     {
4398         sDnsMessages.Clear();
4399 
4400         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4401         AdvanceTime(250);
4402 
4403         VerifyOrQuit(!sDnsMessages.IsEmpty());
4404         dnsMsg = sDnsMessages.GetHead();
4405         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
4406         dnsMsg->ValidateAsProbeFor(host, /* aUnicastRequest */ (probeCount == 0));
4407         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4408     }
4409 
4410     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
4411     {
4412         sDnsMessages.Clear();
4413 
4414         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
4415         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4416 
4417         VerifyOrQuit(!sDnsMessages.IsEmpty());
4418         dnsMsg = sDnsMessages.GetHead();
4419         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 1);
4420         dnsMsg->Validate(host, kInAnswerSection);
4421         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4422     }
4423 
4424     VerifyOrQuit(!sConflictCallback.mWasCalled);
4425 
4426     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4427     Log("Send a response for host name and validate that conflict is detected and callback is called");
4428 
4429     SendResponseWithEmptyKey(hostFullName.AsCString(), kInAnswerSection);
4430     AdvanceTime(1);
4431 
4432     VerifyOrQuit(sConflictCallback.mWasCalled);
4433     VerifyOrQuit(StringMatch(sConflictCallback.mName.AsCString(), host.mHostName, kStringCaseInsensitiveMatch));
4434     VerifyOrQuit(!sConflictCallback.mHasServiceType);
4435 
4436     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
4437     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
4438 
4439     Log("End of test");
4440 
4441     testFreeInstance(sInstance);
4442 }
4443 
4444 //---------------------------------------------------------------------------------------------------------------------
4445 
TestServiceConflict(void)4446 void TestServiceConflict(void)
4447 {
4448     Core             *mdns = InitTest();
4449     Core::Service     service;
4450     const DnsMessage *dnsMsg;
4451     uint16_t          heapAllocations;
4452     DnsNameString     fullServiceName;
4453 
4454     Log("-------------------------------------------------------------------------------------------");
4455     Log("TestServiceConflict");
4456 
4457     service.mHostName            = "myhost";
4458     service.mServiceInstance     = "myservice";
4459     service.mServiceType         = "_srv._udp";
4460     service.mSubTypeLabels       = nullptr;
4461     service.mSubTypeLabelsLength = 0;
4462     service.mTxtData             = kTxtData1;
4463     service.mTxtDataLength       = sizeof(kTxtData1);
4464     service.mPort                = 1234;
4465     service.mPriority            = 1;
4466     service.mWeight              = 2;
4467     service.mTtl                 = 1000;
4468 
4469     fullServiceName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
4470 
4471     AdvanceTime(1);
4472 
4473     heapAllocations = sHeapAllocatedPtrs.GetLength();
4474     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
4475 
4476     // Run the test twice, first run send response with record in Answer section,
4477     // section run in Additional Data section.
4478 
4479     sConflictCallback.Reset();
4480     mdns->SetConflictCallback(HandleConflict);
4481 
4482     for (uint8_t iter = 0; iter < 2; iter++)
4483     {
4484         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4485         Log("Register a `ServiceEntry`, wait for first probe");
4486 
4487         sDnsMessages.Clear();
4488 
4489         sRegCallbacks[0].Reset();
4490         SuccessOrQuit(mdns->RegisterService(service, 0, HandleCallback));
4491 
4492         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4493         AdvanceTime(250);
4494 
4495         VerifyOrQuit(!sDnsMessages.IsEmpty());
4496         dnsMsg = sDnsMessages.GetHead();
4497         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
4498         dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ true);
4499         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4500 
4501         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4502         Log("Send a response claiming the name with record in %s section", (iter == 0) ? "answer" : "additional");
4503 
4504         SendResponseWithEmptyKey(fullServiceName.AsCString(), (iter == 0) ? kInAnswerSection : kInAdditionalSection);
4505         AdvanceTime(1);
4506 
4507         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4508         VerifyOrQuit(sRegCallbacks[0].mError == kErrorDuplicated);
4509 
4510         VerifyOrQuit(!sConflictCallback.mWasCalled);
4511 
4512         sDnsMessages.Clear();
4513 
4514         SuccessOrQuit(mdns->UnregisterService(service));
4515 
4516         AdvanceTime(15000);
4517         VerifyOrQuit(sDnsMessages.IsEmpty());
4518     }
4519 
4520     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4521     Log("Register a `ServiceEntry` and respond to probe to trigger conflict");
4522 
4523     sRegCallbacks[0].Reset();
4524     SuccessOrQuit(mdns->RegisterService(service, 0, HandleCallback));
4525 
4526     VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4527 
4528     SendResponseWithEmptyKey(fullServiceName.AsCString(), kInAnswerSection);
4529     AdvanceTime(1);
4530 
4531     VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4532     VerifyOrQuit(sRegCallbacks[0].mError == kErrorDuplicated);
4533     VerifyOrQuit(!sConflictCallback.mWasCalled);
4534 
4535     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4536     Log("Register the conflicted `ServiceEntry` again, and make sure no probes are sent");
4537 
4538     sRegCallbacks[1].Reset();
4539     sConflictCallback.Reset();
4540     sDnsMessages.Clear();
4541 
4542     SuccessOrQuit(mdns->RegisterService(service, 1, HandleCallback));
4543     AdvanceTime(5000);
4544 
4545     VerifyOrQuit(sRegCallbacks[1].mWasCalled);
4546     VerifyOrQuit(sRegCallbacks[1].mError == kErrorDuplicated);
4547     VerifyOrQuit(!sConflictCallback.mWasCalled);
4548 
4549     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4550     Log("Unregister the conflicted host and register it again immediately, make sure we see probes");
4551 
4552     SuccessOrQuit(mdns->UnregisterService(service));
4553 
4554     sConflictCallback.Reset();
4555     sRegCallbacks[0].Reset();
4556     SuccessOrQuit(mdns->RegisterService(service, 0, HandleSuccessCallback));
4557 
4558     for (uint8_t probeCount = 0; probeCount < 3; probeCount++)
4559     {
4560         sDnsMessages.Clear();
4561 
4562         VerifyOrQuit(!sRegCallbacks[0].mWasCalled);
4563         AdvanceTime(250);
4564 
4565         VerifyOrQuit(!sDnsMessages.IsEmpty());
4566         dnsMsg = sDnsMessages.GetHead();
4567         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 2, /* Addnl */ 0);
4568         dnsMsg->ValidateAsProbeFor(service, /* aUnicastRequest */ (probeCount == 0));
4569         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4570     }
4571 
4572     for (uint8_t anncCount = 0; anncCount < kNumAnnounces; anncCount++)
4573     {
4574         sDnsMessages.Clear();
4575 
4576         AdvanceTime((anncCount == 0) ? 250 : (1U << (anncCount - 1)) * 1000);
4577         VerifyOrQuit(sRegCallbacks[0].mWasCalled);
4578 
4579         VerifyOrQuit(!sDnsMessages.IsEmpty());
4580         dnsMsg = sDnsMessages.GetHead();
4581         dnsMsg->ValidateHeader(kMulticastResponse, /* Q */ 0, /* Ans */ 4, /* Auth */ 0, /* Addnl */ 1);
4582         dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt | kCheckPtr | kCheckServicesPtr);
4583         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4584     }
4585 
4586     VerifyOrQuit(!sConflictCallback.mWasCalled);
4587 
4588     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4589     Log("Send a response for service name and validate that conflict is detected and callback is called");
4590 
4591     SendResponseWithEmptyKey(fullServiceName.AsCString(), kInAnswerSection);
4592     AdvanceTime(1);
4593 
4594     VerifyOrQuit(sConflictCallback.mWasCalled);
4595     VerifyOrQuit(
4596         StringMatch(sConflictCallback.mName.AsCString(), service.mServiceInstance, kStringCaseInsensitiveMatch));
4597     VerifyOrQuit(sConflictCallback.mHasServiceType);
4598     VerifyOrQuit(
4599         StringMatch(sConflictCallback.mServiceType.AsCString(), service.mServiceType, kStringCaseInsensitiveMatch));
4600 
4601     sDnsMessages.Clear();
4602     AdvanceTime(20000);
4603     VerifyOrQuit(sDnsMessages.IsEmpty());
4604 
4605     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
4606     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
4607 
4608     Log("End of test");
4609 
4610     testFreeInstance(sInstance);
4611 }
4612 
4613 //=====================================================================================================================
4614 // Browser/Resolver tests
4615 
4616 struct BrowseCallback : public Allocatable<BrowseCallback>, public LinkedListEntry<BrowseCallback>
4617 {
4618     BrowseCallback *mNext;
4619     DnsName         mServiceType;
4620     DnsName         mSubTypeLabel;
4621     DnsName         mServiceInstance;
4622     uint32_t        mTtl;
4623     bool            mIsSubType;
4624 };
4625 
4626 struct SrvCallback : public Allocatable<SrvCallback>, public LinkedListEntry<SrvCallback>
4627 {
4628     SrvCallback *mNext;
4629     DnsName      mServiceInstance;
4630     DnsName      mServiceType;
4631     DnsName      mHostName;
4632     uint16_t     mPort;
4633     uint16_t     mPriority;
4634     uint16_t     mWeight;
4635     uint32_t     mTtl;
4636 };
4637 
4638 struct TxtCallback : public Allocatable<TxtCallback>, public LinkedListEntry<TxtCallback>
4639 {
4640     static constexpr uint16_t kMaxTxtDataLength = 100;
4641 
Matchesot::Dns::Multicast::TxtCallback4642     template <uint16_t kSize> bool Matches(const uint8_t (&aData)[kSize]) const
4643     {
4644         return (mTxtDataLength == kSize) && (memcmp(mTxtData, aData, kSize) == 0);
4645     }
4646 
4647     TxtCallback *mNext;
4648     DnsName      mServiceInstance;
4649     DnsName      mServiceType;
4650     uint8_t      mTxtData[kMaxTxtDataLength];
4651     uint16_t     mTxtDataLength;
4652     uint32_t     mTtl;
4653 };
4654 
4655 struct AddrCallback : public Allocatable<AddrCallback>, public LinkedListEntry<AddrCallback>
4656 {
4657     static constexpr uint16_t kMaxNumAddrs = 16;
4658 
Containsot::Dns::Multicast::AddrCallback4659     bool Contains(const AddrAndTtl &aAddrAndTtl) const
4660     {
4661         bool contains = false;
4662 
4663         for (uint16_t index = 0; index < mNumAddrs; index++)
4664         {
4665             if (mAddrAndTtls[index] == aAddrAndTtl)
4666             {
4667                 contains = true;
4668                 break;
4669             }
4670         }
4671 
4672         return contains;
4673     }
4674 
Matchesot::Dns::Multicast::AddrCallback4675     bool Matches(const AddrAndTtl *aAddrAndTtls, uint16_t aNumAddrs) const
4676     {
4677         bool matches = true;
4678 
4679         VerifyOrExit(aNumAddrs == mNumAddrs, matches = false);
4680 
4681         for (uint16_t index = 0; index < mNumAddrs; index++)
4682         {
4683             if (!Contains(aAddrAndTtls[index]))
4684             {
4685                 ExitNow(matches = false);
4686             }
4687         }
4688 
4689     exit:
4690         return matches;
4691     }
4692 
4693     AddrCallback *mNext;
4694     DnsName       mHostName;
4695     AddrAndTtl    mAddrAndTtls[kMaxNumAddrs];
4696     uint16_t      mNumAddrs;
4697 };
4698 
4699 OwningList<BrowseCallback> sBrowseCallbacks;
4700 OwningList<SrvCallback>    sSrvCallbacks;
4701 OwningList<TxtCallback>    sTxtCallbacks;
4702 OwningList<AddrCallback>   sAddrCallbacks;
4703 
HandleBrowseResult(otInstance * aInstance,const otMdnsBrowseResult * aResult)4704 void HandleBrowseResult(otInstance *aInstance, const otMdnsBrowseResult *aResult)
4705 {
4706     BrowseCallback *entry;
4707 
4708     VerifyOrQuit(aInstance == sInstance);
4709     VerifyOrQuit(aResult != nullptr);
4710     VerifyOrQuit(aResult->mServiceType != nullptr);
4711     VerifyOrQuit(aResult->mServiceInstance != nullptr);
4712     VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
4713 
4714     Log("Browse callback: %s (subtype:%s) -> %s ttl:%lu", aResult->mServiceType,
4715         aResult->mSubTypeLabel == nullptr ? "(null)" : aResult->mSubTypeLabel, aResult->mServiceInstance,
4716         ToUlong(aResult->mTtl));
4717 
4718     entry = BrowseCallback::Allocate();
4719     VerifyOrQuit(entry != nullptr);
4720 
4721     entry->mServiceType.CopyFrom(aResult->mServiceType);
4722     entry->mSubTypeLabel.CopyFrom(aResult->mSubTypeLabel);
4723     entry->mServiceInstance.CopyFrom(aResult->mServiceInstance);
4724     entry->mTtl       = aResult->mTtl;
4725     entry->mIsSubType = (aResult->mSubTypeLabel != nullptr);
4726 
4727     sBrowseCallbacks.PushAfterTail(*entry);
4728 }
4729 
HandleBrowseResultAlternate(otInstance * aInstance,const otMdnsBrowseResult * aResult)4730 void HandleBrowseResultAlternate(otInstance *aInstance, const otMdnsBrowseResult *aResult)
4731 {
4732     Log("Alternate browse callback is called");
4733     HandleBrowseResult(aInstance, aResult);
4734 }
4735 
HandleSrvResult(otInstance * aInstance,const otMdnsSrvResult * aResult)4736 void HandleSrvResult(otInstance *aInstance, const otMdnsSrvResult *aResult)
4737 {
4738     SrvCallback *entry;
4739 
4740     VerifyOrQuit(aInstance == sInstance);
4741     VerifyOrQuit(aResult != nullptr);
4742     VerifyOrQuit(aResult->mServiceInstance != nullptr);
4743     VerifyOrQuit(aResult->mServiceType != nullptr);
4744     VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
4745 
4746     if (aResult->mTtl != 0)
4747     {
4748         VerifyOrQuit(aResult->mHostName != nullptr);
4749 
4750         Log("SRV callback: %s %s, host:%s port:%u, prio:%u, weight:%u, ttl:%lu", aResult->mServiceInstance,
4751             aResult->mServiceType, aResult->mHostName, aResult->mPort, aResult->mPriority, aResult->mWeight,
4752             ToUlong(aResult->mTtl));
4753     }
4754     else
4755     {
4756         Log("SRV callback: %s %s, ttl:%lu", aResult->mServiceInstance, aResult->mServiceType, ToUlong(aResult->mTtl));
4757     }
4758 
4759     entry = SrvCallback::Allocate();
4760     VerifyOrQuit(entry != nullptr);
4761 
4762     entry->mServiceInstance.CopyFrom(aResult->mServiceInstance);
4763     entry->mServiceType.CopyFrom(aResult->mServiceType);
4764     entry->mHostName.CopyFrom(aResult->mHostName);
4765     entry->mPort     = aResult->mPort;
4766     entry->mPriority = aResult->mPriority;
4767     entry->mWeight   = aResult->mWeight;
4768     entry->mTtl      = aResult->mTtl;
4769 
4770     sSrvCallbacks.PushAfterTail(*entry);
4771 }
4772 
HandleSrvResultAlternate(otInstance * aInstance,const otMdnsSrvResult * aResult)4773 void HandleSrvResultAlternate(otInstance *aInstance, const otMdnsSrvResult *aResult)
4774 {
4775     Log("Alternate SRV callback is called");
4776     HandleSrvResult(aInstance, aResult);
4777 }
4778 
HandleTxtResult(otInstance * aInstance,const otMdnsTxtResult * aResult)4779 void HandleTxtResult(otInstance *aInstance, const otMdnsTxtResult *aResult)
4780 {
4781     TxtCallback *entry;
4782 
4783     VerifyOrQuit(aInstance == sInstance);
4784     VerifyOrQuit(aResult != nullptr);
4785     VerifyOrQuit(aResult->mServiceInstance != nullptr);
4786     VerifyOrQuit(aResult->mServiceType != nullptr);
4787     VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
4788 
4789     VerifyOrQuit(aResult->mTxtDataLength <= TxtCallback::kMaxTxtDataLength);
4790 
4791     if (aResult->mTtl != 0)
4792     {
4793         VerifyOrQuit(aResult->mTxtData != nullptr);
4794 
4795         Log("TXT callback: %s %s, len:%u, ttl:%lu", aResult->mServiceInstance, aResult->mServiceType,
4796             aResult->mTxtDataLength, ToUlong(aResult->mTtl));
4797     }
4798     else
4799     {
4800         Log("TXT callback: %s %s, ttl:%lu", aResult->mServiceInstance, aResult->mServiceType, ToUlong(aResult->mTtl));
4801     }
4802 
4803     entry = TxtCallback::Allocate();
4804     VerifyOrQuit(entry != nullptr);
4805 
4806     entry->mServiceInstance.CopyFrom(aResult->mServiceInstance);
4807     entry->mServiceType.CopyFrom(aResult->mServiceType);
4808     entry->mTxtDataLength = aResult->mTxtDataLength;
4809     memcpy(entry->mTxtData, aResult->mTxtData, aResult->mTxtDataLength);
4810     entry->mTtl = aResult->mTtl;
4811 
4812     sTxtCallbacks.PushAfterTail(*entry);
4813 }
4814 
HandleTxtResultAlternate(otInstance * aInstance,const otMdnsTxtResult * aResult)4815 void HandleTxtResultAlternate(otInstance *aInstance, const otMdnsTxtResult *aResult)
4816 {
4817     Log("Alternate TXT callback is called");
4818     HandleTxtResult(aInstance, aResult);
4819 }
4820 
HandleAddrResult(otInstance * aInstance,const otMdnsAddressResult * aResult)4821 void HandleAddrResult(otInstance *aInstance, const otMdnsAddressResult *aResult)
4822 {
4823     AddrCallback *entry;
4824 
4825     VerifyOrQuit(aInstance == sInstance);
4826     VerifyOrQuit(aResult != nullptr);
4827     VerifyOrQuit(aResult->mHostName != nullptr);
4828     VerifyOrQuit(aResult->mInfraIfIndex == kInfraIfIndex);
4829 
4830     VerifyOrQuit(aResult->mAddressesLength <= AddrCallback::kMaxNumAddrs);
4831 
4832     entry = AddrCallback::Allocate();
4833     VerifyOrQuit(entry != nullptr);
4834 
4835     entry->mHostName.CopyFrom(aResult->mHostName);
4836     entry->mNumAddrs = aResult->mAddressesLength;
4837 
4838     Log("Addr callback: %s, num:%u", aResult->mHostName, aResult->mAddressesLength);
4839 
4840     for (uint16_t index = 0; index < aResult->mAddressesLength; index++)
4841     {
4842         entry->mAddrAndTtls[index].mAddress = AsCoreType(&aResult->mAddresses[index].mAddress);
4843         entry->mAddrAndTtls[index].mTtl     = aResult->mAddresses[index].mTtl;
4844 
4845         Log(" - %s, ttl:%lu", entry->mAddrAndTtls[index].mAddress.ToString().AsCString(),
4846             ToUlong(entry->mAddrAndTtls[index].mTtl));
4847     }
4848 
4849     sAddrCallbacks.PushAfterTail(*entry);
4850 }
4851 
HandleAddrResultAlternate(otInstance * aInstance,const otMdnsAddressResult * aResult)4852 void HandleAddrResultAlternate(otInstance *aInstance, const otMdnsAddressResult *aResult)
4853 {
4854     Log("Alternate addr callback is called");
4855     HandleAddrResult(aInstance, aResult);
4856 }
4857 
4858 //---------------------------------------------------------------------------------------------------------------------
4859 
TestBrowser(void)4860 void TestBrowser(void)
4861 {
4862     Core                 *mdns = InitTest();
4863     Core::Browser         browser;
4864     Core::Browser         browser2;
4865     const DnsMessage     *dnsMsg;
4866     const BrowseCallback *browseCallback;
4867     uint16_t              heapAllocations;
4868 
4869     Log("-------------------------------------------------------------------------------------------");
4870     Log("TestBrowser");
4871 
4872     AdvanceTime(1);
4873 
4874     heapAllocations = sHeapAllocatedPtrs.GetLength();
4875     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
4876 
4877     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4878     Log("Start a browser. Validate initial queries.");
4879 
4880     ClearAllBytes(browser);
4881 
4882     browser.mServiceType  = "_srv._udp";
4883     browser.mSubTypeLabel = nullptr;
4884     browser.mInfraIfIndex = kInfraIfIndex;
4885     browser.mCallback     = HandleBrowseResult;
4886 
4887     sDnsMessages.Clear();
4888     SuccessOrQuit(mdns->StartBrowser(browser));
4889 
4890     for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; queryCount++)
4891     {
4892         sDnsMessages.Clear();
4893 
4894         AdvanceTime((queryCount == 0) ? 125 : (1U << (queryCount - 1)) * 1000);
4895 
4896         VerifyOrQuit(!sDnsMessages.IsEmpty());
4897         dnsMsg = sDnsMessages.GetHead();
4898         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
4899         dnsMsg->ValidateAsQueryFor(browser);
4900         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
4901     }
4902 
4903     sDnsMessages.Clear();
4904 
4905     AdvanceTime(20000);
4906     VerifyOrQuit(sDnsMessages.IsEmpty());
4907 
4908     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4909     Log("Send a response. Validate callback result.");
4910 
4911     sBrowseCallbacks.Clear();
4912 
4913     SendPtrResponse("_srv._udp.local.", "mysrv._srv._udp.local.", 120, kInAnswerSection);
4914 
4915     AdvanceTime(1);
4916 
4917     VerifyOrQuit(!sBrowseCallbacks.IsEmpty());
4918     browseCallback = sBrowseCallbacks.GetHead();
4919     VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
4920     VerifyOrQuit(!browseCallback->mIsSubType);
4921     VerifyOrQuit(browseCallback->mServiceInstance.Matches("mysrv"));
4922     VerifyOrQuit(browseCallback->mTtl == 120);
4923     VerifyOrQuit(browseCallback->GetNext() == nullptr);
4924 
4925     VerifyOrQuit(sDnsMessages.IsEmpty());
4926 
4927     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4928     Log("Send another response. Validate callback result.");
4929 
4930     AdvanceTime(10000);
4931 
4932     sBrowseCallbacks.Clear();
4933 
4934     SendPtrResponse("_srv._udp.local.", "awesome._srv._udp.local.", 500, kInAnswerSection);
4935 
4936     AdvanceTime(1);
4937 
4938     VerifyOrQuit(!sBrowseCallbacks.IsEmpty());
4939     browseCallback = sBrowseCallbacks.GetHead();
4940     VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
4941     VerifyOrQuit(!browseCallback->mIsSubType);
4942     VerifyOrQuit(browseCallback->mServiceInstance.Matches("awesome"));
4943     VerifyOrQuit(browseCallback->mTtl == 500);
4944     VerifyOrQuit(browseCallback->GetNext() == nullptr);
4945 
4946     VerifyOrQuit(sDnsMessages.IsEmpty());
4947 
4948     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4949     Log("Start another browser for the same service and different callback. Validate results.");
4950 
4951     AdvanceTime(5000);
4952 
4953     browser2.mServiceType  = "_srv._udp";
4954     browser2.mSubTypeLabel = nullptr;
4955     browser2.mInfraIfIndex = kInfraIfIndex;
4956     browser2.mCallback     = HandleBrowseResultAlternate;
4957 
4958     sBrowseCallbacks.Clear();
4959 
4960     SuccessOrQuit(mdns->StartBrowser(browser2));
4961 
4962     browseCallback = sBrowseCallbacks.GetHead();
4963 
4964     for (uint8_t iter = 0; iter < 2; iter++)
4965     {
4966         VerifyOrQuit(browseCallback != nullptr);
4967 
4968         VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
4969         VerifyOrQuit(!browseCallback->mIsSubType);
4970 
4971         if (browseCallback->mServiceInstance.Matches("awesome"))
4972         {
4973             VerifyOrQuit(browseCallback->mTtl == 500);
4974         }
4975         else if (browseCallback->mServiceInstance.Matches("mysrv"))
4976         {
4977             VerifyOrQuit(browseCallback->mTtl == 120);
4978         }
4979         else
4980         {
4981             VerifyOrQuit(false);
4982         }
4983 
4984         browseCallback = browseCallback->GetNext();
4985     }
4986 
4987     VerifyOrQuit(browseCallback == nullptr);
4988 
4989     AdvanceTime(5000);
4990 
4991     VerifyOrQuit(sDnsMessages.IsEmpty());
4992 
4993     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
4994     Log("Start same browser again and check the returned error.");
4995 
4996     sBrowseCallbacks.Clear();
4997 
4998     VerifyOrQuit(mdns->StartBrowser(browser2) == kErrorAlready);
4999 
5000     AdvanceTime(5000);
5001 
5002     VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5003 
5004     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5005     Log("Send a goodbye response. Validate result callback for both browsers.");
5006 
5007     SendPtrResponse("_srv._udp.local.", "awesome._srv._udp.local.", 0, kInAnswerSection);
5008 
5009     AdvanceTime(1);
5010 
5011     browseCallback = sBrowseCallbacks.GetHead();
5012 
5013     for (uint8_t iter = 0; iter < 2; iter++)
5014     {
5015         VerifyOrQuit(browseCallback != nullptr);
5016 
5017         VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
5018         VerifyOrQuit(!browseCallback->mIsSubType);
5019         VerifyOrQuit(browseCallback->mServiceInstance.Matches("awesome"));
5020         VerifyOrQuit(browseCallback->mTtl == 0);
5021 
5022         browseCallback = browseCallback->GetNext();
5023     }
5024 
5025     VerifyOrQuit(browseCallback == nullptr);
5026 
5027     VerifyOrQuit(sDnsMessages.IsEmpty());
5028 
5029     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5030     Log("Send a response with no changes, validate that no callback is invoked.");
5031 
5032     sBrowseCallbacks.Clear();
5033 
5034     SendPtrResponse("_srv._udp.local.", "mysrv._srv._udp.local.", 120, kInAnswerSection);
5035 
5036     AdvanceTime(1);
5037 
5038     VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5039     VerifyOrQuit(sDnsMessages.IsEmpty());
5040 
5041     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5042     Log("Stop the second browser.");
5043 
5044     sBrowseCallbacks.Clear();
5045 
5046     SuccessOrQuit(mdns->StopBrowser(browser2));
5047 
5048     AdvanceTime(5000);
5049 
5050     VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5051     VerifyOrQuit(sDnsMessages.IsEmpty());
5052 
5053     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5054     Log("Check query is sent at 80 percentage of TTL and then respond to it.");
5055 
5056     // First query should be sent at 80-82% of TTL of 120 second (96.0-98.4 sec).
5057     // We wait for 100 second. Note that 5 seconds already passed in the
5058     // previous step.
5059 
5060     AdvanceTime(91 * 1000 - 1);
5061 
5062     VerifyOrQuit(sDnsMessages.IsEmpty());
5063 
5064     AdvanceTime(4 * 1000 + 1);
5065 
5066     VerifyOrQuit(!sDnsMessages.IsEmpty());
5067     dnsMsg = sDnsMessages.GetHead();
5068     dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5069     dnsMsg->ValidateAsQueryFor(browser);
5070     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5071 
5072     sDnsMessages.Clear();
5073     VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5074 
5075     AdvanceTime(10);
5076 
5077     SendPtrResponse("_srv._udp.local.", "mysrv._srv._udp.local.", 120, kInAnswerSection);
5078 
5079     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5080     Log("Check queries are sent at 80, 85, 90, 95 percentages of TTL.");
5081 
5082     for (uint8_t queryCount = 0; queryCount < kNumRefreshQueries; queryCount++)
5083     {
5084         if (queryCount == 0)
5085         {
5086             // First query is expected in 80-82% of TTL, so
5087             // 80% of 120 = 96.0, 82% of 120 = 98.4
5088 
5089             AdvanceTime(96 * 1000 - 1);
5090         }
5091         else
5092         {
5093             // Next query should happen within 3%-5% of TTL
5094             // from previous query. We wait 3% of TTL here.
5095             AdvanceTime(3600 - 1);
5096         }
5097 
5098         VerifyOrQuit(sDnsMessages.IsEmpty());
5099 
5100         // Wait for 2% of TTL of 120 which is 2.4 sec.
5101 
5102         AdvanceTime(2400 + 1);
5103 
5104         VerifyOrQuit(!sDnsMessages.IsEmpty());
5105         dnsMsg = sDnsMessages.GetHead();
5106         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5107         dnsMsg->ValidateAsQueryFor(browser);
5108         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5109 
5110         sDnsMessages.Clear();
5111         VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5112     }
5113 
5114     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5115     Log("Check TTL timeout and callback result.");
5116 
5117     AdvanceTime(6 * 1000);
5118 
5119     VerifyOrQuit(!sBrowseCallbacks.IsEmpty());
5120 
5121     browseCallback = sBrowseCallbacks.GetHead();
5122     VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
5123     VerifyOrQuit(!browseCallback->mIsSubType);
5124     VerifyOrQuit(browseCallback->mServiceInstance.Matches("mysrv"));
5125     VerifyOrQuit(browseCallback->mTtl == 0);
5126     VerifyOrQuit(browseCallback->GetNext() == nullptr);
5127 
5128     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5129 
5130     sBrowseCallbacks.Clear();
5131     sDnsMessages.Clear();
5132 
5133     AdvanceTime(200 * 1000);
5134 
5135     VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5136     VerifyOrQuit(sDnsMessages.IsEmpty());
5137 
5138     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5139     Log("Send a new response and make sure result callback is invoked");
5140 
5141     SendPtrResponse("_srv._udp.local.", "great._srv._udp.local.", 200, kInAdditionalSection);
5142 
5143     AdvanceTime(1);
5144 
5145     browseCallback = sBrowseCallbacks.GetHead();
5146 
5147     VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
5148     VerifyOrQuit(!browseCallback->mIsSubType);
5149     VerifyOrQuit(browseCallback->mServiceInstance.Matches("great"));
5150     VerifyOrQuit(browseCallback->mTtl == 200);
5151     VerifyOrQuit(browseCallback->GetNext() == nullptr);
5152 
5153     sBrowseCallbacks.Clear();
5154 
5155     AdvanceTime(150 * 1000);
5156 
5157     VerifyOrQuit(sDnsMessages.IsEmpty());
5158     VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5159 
5160     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5161     Log("Stop the browser. There is no active browser for this service. Ensure no queries are sent");
5162 
5163     sBrowseCallbacks.Clear();
5164 
5165     SuccessOrQuit(mdns->StopBrowser(browser));
5166 
5167     AdvanceTime(100 * 1000);
5168 
5169     VerifyOrQuit(sBrowseCallbacks.IsEmpty());
5170     VerifyOrQuit(sDnsMessages.IsEmpty());
5171 
5172     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5173     Log("Start browser again. Validate that initial queries are sent again");
5174 
5175     SuccessOrQuit(mdns->StartBrowser(browser));
5176 
5177     AdvanceTime(125);
5178 
5179     VerifyOrQuit(!sDnsMessages.IsEmpty());
5180     dnsMsg = sDnsMessages.GetHead();
5181     dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5182     dnsMsg->ValidateAsQueryFor(browser);
5183     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5184 
5185     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5186     Log("Send a response after the first initial query");
5187 
5188     sDnsMessages.Clear();
5189 
5190     SendPtrResponse("_srv._udp.local.", "mysrv._srv._udp.local.", 120, kInAnswerSection);
5191 
5192     AdvanceTime(1);
5193 
5194     browseCallback = sBrowseCallbacks.GetHead();
5195 
5196     VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
5197     VerifyOrQuit(!browseCallback->mIsSubType);
5198     VerifyOrQuit(browseCallback->mServiceInstance.Matches("mysrv"));
5199     VerifyOrQuit(browseCallback->mTtl == 120);
5200     VerifyOrQuit(browseCallback->GetNext() == nullptr);
5201 
5202     sBrowseCallbacks.Clear();
5203 
5204     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5205     Log("Validate initial esquires are still sent and include known-answer");
5206 
5207     for (uint8_t queryCount = 1; queryCount < kNumInitalQueries; queryCount++)
5208     {
5209         sDnsMessages.Clear();
5210 
5211         AdvanceTime((1U << (queryCount - 1)) * 1000);
5212 
5213         VerifyOrQuit(!sDnsMessages.IsEmpty());
5214         dnsMsg = sDnsMessages.GetHead();
5215         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 0);
5216         dnsMsg->ValidateAsQueryFor(browser);
5217         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5218     }
5219 
5220     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5221 
5222     sDnsMessages.Clear();
5223     AdvanceTime(50 * 1000);
5224     VerifyOrQuit(sDnsMessages.IsEmpty());
5225 
5226     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
5227     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
5228 
5229     Log("End of test");
5230 
5231     testFreeInstance(sInstance);
5232 }
5233 
TestSrvResolver(void)5234 void TestSrvResolver(void)
5235 {
5236     Core              *mdns = InitTest();
5237     Core::SrvResolver  resolver;
5238     Core::SrvResolver  resolver2;
5239     const DnsMessage  *dnsMsg;
5240     const SrvCallback *srvCallback;
5241     uint16_t           heapAllocations;
5242 
5243     Log("-------------------------------------------------------------------------------------------");
5244     Log("TestSrvResolver");
5245 
5246     AdvanceTime(1);
5247 
5248     heapAllocations = sHeapAllocatedPtrs.GetLength();
5249     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
5250 
5251     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5252     Log("Start a SRV resolver. Validate initial queries.");
5253 
5254     ClearAllBytes(resolver);
5255 
5256     resolver.mServiceInstance = "mysrv";
5257     resolver.mServiceType     = "_srv._udp";
5258     resolver.mInfraIfIndex    = kInfraIfIndex;
5259     resolver.mCallback        = HandleSrvResult;
5260 
5261     sDnsMessages.Clear();
5262     SuccessOrQuit(mdns->StartSrvResolver(resolver));
5263 
5264     for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; queryCount++)
5265     {
5266         sDnsMessages.Clear();
5267 
5268         AdvanceTime((queryCount == 0) ? 125 : (1U << (queryCount - 1)) * 1000);
5269 
5270         VerifyOrQuit(!sDnsMessages.IsEmpty());
5271         dnsMsg = sDnsMessages.GetHead();
5272         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5273         dnsMsg->ValidateAsQueryFor(resolver);
5274         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5275     }
5276 
5277     sDnsMessages.Clear();
5278 
5279     AdvanceTime(20 * 1000);
5280     VerifyOrQuit(sDnsMessages.IsEmpty());
5281 
5282     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5283     Log("Send a response. Validate callback result.");
5284 
5285     sSrvCallbacks.Clear();
5286 
5287     SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 0, 1, 120, kInAnswerSection);
5288 
5289     AdvanceTime(1);
5290 
5291     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5292     srvCallback = sSrvCallbacks.GetHead();
5293     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5294     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5295     VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
5296     VerifyOrQuit(srvCallback->mPort == 1234);
5297     VerifyOrQuit(srvCallback->mPriority == 0);
5298     VerifyOrQuit(srvCallback->mWeight == 1);
5299     VerifyOrQuit(srvCallback->mTtl == 120);
5300     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5301 
5302     VerifyOrQuit(sDnsMessages.IsEmpty());
5303 
5304     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5305     Log("Send an updated response changing host name. Validate callback result.");
5306 
5307     AdvanceTime(1000);
5308 
5309     sSrvCallbacks.Clear();
5310 
5311     SendSrvResponse("mysrv._srv._udp.local.", "myhost2.local.", 1234, 0, 1, 120, kInAnswerSection);
5312 
5313     AdvanceTime(1);
5314 
5315     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5316     srvCallback = sSrvCallbacks.GetHead();
5317     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5318     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5319     VerifyOrQuit(srvCallback->mHostName.Matches("myhost2"));
5320     VerifyOrQuit(srvCallback->mPort == 1234);
5321     VerifyOrQuit(srvCallback->mPriority == 0);
5322     VerifyOrQuit(srvCallback->mWeight == 1);
5323     VerifyOrQuit(srvCallback->mTtl == 120);
5324     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5325 
5326     VerifyOrQuit(sDnsMessages.IsEmpty());
5327 
5328     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5329     Log("Send an updated response changing port. Validate callback result.");
5330 
5331     AdvanceTime(1000);
5332 
5333     sSrvCallbacks.Clear();
5334 
5335     SendSrvResponse("mysrv._srv._udp.local.", "myhost2.local.", 4567, 0, 1, 120, kInAnswerSection);
5336 
5337     AdvanceTime(1);
5338 
5339     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5340     srvCallback = sSrvCallbacks.GetHead();
5341     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5342     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5343     VerifyOrQuit(srvCallback->mHostName.Matches("myhost2"));
5344     VerifyOrQuit(srvCallback->mPort == 4567);
5345     VerifyOrQuit(srvCallback->mPriority == 0);
5346     VerifyOrQuit(srvCallback->mWeight == 1);
5347     VerifyOrQuit(srvCallback->mTtl == 120);
5348     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5349 
5350     VerifyOrQuit(sDnsMessages.IsEmpty());
5351 
5352     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5353     Log("Send an updated response changing TTL. Validate callback result.");
5354 
5355     AdvanceTime(1000);
5356 
5357     sSrvCallbacks.Clear();
5358 
5359     SendSrvResponse("mysrv._srv._udp.local.", "myhost2.local.", 4567, 0, 1, 0, kInAnswerSection);
5360 
5361     AdvanceTime(1);
5362 
5363     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5364     srvCallback = sSrvCallbacks.GetHead();
5365     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5366     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5367     VerifyOrQuit(srvCallback->mHostName.Matches(""));
5368     VerifyOrQuit(srvCallback->mPort == 4567);
5369     VerifyOrQuit(srvCallback->mPriority == 0);
5370     VerifyOrQuit(srvCallback->mWeight == 1);
5371     VerifyOrQuit(srvCallback->mTtl == 0);
5372     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5373 
5374     VerifyOrQuit(sDnsMessages.IsEmpty());
5375 
5376     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5377     Log("Send an updated response changing a bunch of things. Validate callback result.");
5378 
5379     AdvanceTime(1000);
5380 
5381     sSrvCallbacks.Clear();
5382 
5383     SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
5384 
5385     AdvanceTime(1);
5386 
5387     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5388     srvCallback = sSrvCallbacks.GetHead();
5389     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5390     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5391     VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
5392     VerifyOrQuit(srvCallback->mPort == 1234);
5393     VerifyOrQuit(srvCallback->mPriority == 2);
5394     VerifyOrQuit(srvCallback->mWeight == 3);
5395     VerifyOrQuit(srvCallback->mTtl == 120);
5396     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5397 
5398     VerifyOrQuit(sDnsMessages.IsEmpty());
5399 
5400     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5401     Log("Send a response with no changes. Validate callback is not invoked.");
5402 
5403     AdvanceTime(1000);
5404 
5405     sSrvCallbacks.Clear();
5406 
5407     SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
5408 
5409     AdvanceTime(1);
5410 
5411     VerifyOrQuit(sSrvCallbacks.IsEmpty());
5412     VerifyOrQuit(sDnsMessages.IsEmpty());
5413 
5414     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5415     Log("Start another resolver for the same service and different callback. Validate results.");
5416 
5417     ClearAllBytes(resolver2);
5418 
5419     resolver2.mServiceInstance = "mysrv";
5420     resolver2.mServiceType     = "_srv._udp";
5421     resolver2.mInfraIfIndex    = kInfraIfIndex;
5422     resolver2.mCallback        = HandleSrvResultAlternate;
5423 
5424     sSrvCallbacks.Clear();
5425 
5426     SuccessOrQuit(mdns->StartSrvResolver(resolver2));
5427 
5428     AdvanceTime(1);
5429 
5430     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5431     srvCallback = sSrvCallbacks.GetHead();
5432     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5433     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5434     VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
5435     VerifyOrQuit(srvCallback->mPort == 1234);
5436     VerifyOrQuit(srvCallback->mPriority == 2);
5437     VerifyOrQuit(srvCallback->mWeight == 3);
5438     VerifyOrQuit(srvCallback->mTtl == 120);
5439     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5440 
5441     VerifyOrQuit(sDnsMessages.IsEmpty());
5442 
5443     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5444     Log("Start same resolver again and check the returned error.");
5445 
5446     sSrvCallbacks.Clear();
5447 
5448     VerifyOrQuit(mdns->StartSrvResolver(resolver2) == kErrorAlready);
5449 
5450     AdvanceTime(5000);
5451 
5452     VerifyOrQuit(sSrvCallbacks.IsEmpty());
5453 
5454     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5455     Log("Check query is sent at 80 percentage of TTL and then respond to it.");
5456 
5457     SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
5458 
5459     // First query should be sent at 80-82% of TTL of 120 second (96.0-98.4 sec).
5460     // We wait for 100 second. Note that 5 seconds already passed in the
5461     // previous step.
5462 
5463     AdvanceTime(96 * 1000 - 1);
5464 
5465     VerifyOrQuit(sDnsMessages.IsEmpty());
5466 
5467     AdvanceTime(4 * 1000 + 1);
5468 
5469     VerifyOrQuit(!sDnsMessages.IsEmpty());
5470     dnsMsg = sDnsMessages.GetHead();
5471     dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5472     dnsMsg->ValidateAsQueryFor(resolver);
5473     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5474 
5475     sDnsMessages.Clear();
5476     VerifyOrQuit(sSrvCallbacks.IsEmpty());
5477 
5478     AdvanceTime(10);
5479 
5480     SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
5481 
5482     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5483     Log("Check queries are sent at 80, 85, 90, 95 percentages of TTL.");
5484 
5485     for (uint8_t queryCount = 0; queryCount < kNumRefreshQueries; queryCount++)
5486     {
5487         if (queryCount == 0)
5488         {
5489             // First query is expected in 80-82% of TTL, so
5490             // 80% of 120 = 96.0, 82% of 120 = 98.4
5491 
5492             AdvanceTime(96 * 1000 - 1);
5493         }
5494         else
5495         {
5496             // Next query should happen within 3%-5% of TTL
5497             // from previous query. We wait 3% of TTL here.
5498             AdvanceTime(3600 - 1);
5499         }
5500 
5501         VerifyOrQuit(sDnsMessages.IsEmpty());
5502 
5503         // Wait for 2% of TTL of 120 which is 2.4 sec.
5504 
5505         AdvanceTime(2400 + 1);
5506 
5507         VerifyOrQuit(!sDnsMessages.IsEmpty());
5508         dnsMsg = sDnsMessages.GetHead();
5509         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5510         dnsMsg->ValidateAsQueryFor(resolver);
5511         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5512 
5513         sDnsMessages.Clear();
5514         VerifyOrQuit(sSrvCallbacks.IsEmpty());
5515     }
5516 
5517     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5518     Log("Check TTL timeout and callback result.");
5519 
5520     AdvanceTime(6 * 1000);
5521 
5522     srvCallback = sSrvCallbacks.GetHead();
5523 
5524     for (uint8_t iter = 0; iter < 2; iter++)
5525     {
5526         VerifyOrQuit(srvCallback != nullptr);
5527         VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5528         VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5529         VerifyOrQuit(srvCallback->mTtl == 0);
5530         srvCallback = srvCallback->GetNext();
5531     }
5532 
5533     VerifyOrQuit(srvCallback == nullptr);
5534 
5535     VerifyOrQuit(sDnsMessages.IsEmpty());
5536 
5537     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5538 
5539     sSrvCallbacks.Clear();
5540     sDnsMessages.Clear();
5541 
5542     AdvanceTime(200 * 1000);
5543 
5544     VerifyOrQuit(sSrvCallbacks.IsEmpty());
5545     VerifyOrQuit(sDnsMessages.IsEmpty());
5546 
5547     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5548     Log("Stop the second resolver");
5549 
5550     sSrvCallbacks.Clear();
5551 
5552     SuccessOrQuit(mdns->StopSrvResolver(resolver2));
5553 
5554     AdvanceTime(100 * 1000);
5555 
5556     VerifyOrQuit(sSrvCallbacks.IsEmpty());
5557     VerifyOrQuit(sDnsMessages.IsEmpty());
5558 
5559     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5560     Log("Send a new response and make sure result callback is invoked");
5561 
5562     SendSrvResponse("mysrv._srv._udp.local.", "myhost.local.", 1234, 2, 3, 120, kInAnswerSection);
5563 
5564     AdvanceTime(1);
5565 
5566     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5567     srvCallback = sSrvCallbacks.GetHead();
5568     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5569     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5570     VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
5571     VerifyOrQuit(srvCallback->mPort == 1234);
5572     VerifyOrQuit(srvCallback->mPriority == 2);
5573     VerifyOrQuit(srvCallback->mWeight == 3);
5574     VerifyOrQuit(srvCallback->mTtl == 120);
5575     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5576 
5577     VerifyOrQuit(sDnsMessages.IsEmpty());
5578 
5579     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5580     Log("Stop the resolver. There is no active resolver. Ensure no queries are sent");
5581 
5582     sSrvCallbacks.Clear();
5583 
5584     SuccessOrQuit(mdns->StopSrvResolver(resolver));
5585 
5586     AdvanceTime(20 * 1000);
5587 
5588     VerifyOrQuit(sSrvCallbacks.IsEmpty());
5589     VerifyOrQuit(sDnsMessages.IsEmpty());
5590 
5591     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5592     Log("Restart the resolver with more than half of TTL remaining.");
5593     Log("Ensure cached entry is reported in the result callback and no queries are sent.");
5594 
5595     SuccessOrQuit(mdns->StartSrvResolver(resolver));
5596 
5597     AdvanceTime(1);
5598 
5599     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5600     srvCallback = sSrvCallbacks.GetHead();
5601     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5602     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5603     VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
5604     VerifyOrQuit(srvCallback->mPort == 1234);
5605     VerifyOrQuit(srvCallback->mPriority == 2);
5606     VerifyOrQuit(srvCallback->mWeight == 3);
5607     VerifyOrQuit(srvCallback->mTtl == 120);
5608     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5609 
5610     VerifyOrQuit(sDnsMessages.IsEmpty());
5611 
5612     AdvanceTime(20 * 1000);
5613 
5614     VerifyOrQuit(sDnsMessages.IsEmpty());
5615 
5616     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5617     Log("Stop and start the resolver again after less than half TTL remaining.");
5618     Log("Ensure cached entry is still reported in the result callback but queries should be sent");
5619 
5620     sSrvCallbacks.Clear();
5621 
5622     SuccessOrQuit(mdns->StopSrvResolver(resolver));
5623 
5624     AdvanceTime(25 * 1000);
5625 
5626     SuccessOrQuit(mdns->StartSrvResolver(resolver));
5627 
5628     AdvanceTime(1);
5629 
5630     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
5631     srvCallback = sSrvCallbacks.GetHead();
5632     VerifyOrQuit(srvCallback->mServiceInstance.Matches("mysrv"));
5633     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
5634     VerifyOrQuit(srvCallback->mHostName.Matches("myhost"));
5635     VerifyOrQuit(srvCallback->mPort == 1234);
5636     VerifyOrQuit(srvCallback->mPriority == 2);
5637     VerifyOrQuit(srvCallback->mWeight == 3);
5638     VerifyOrQuit(srvCallback->mTtl == 120);
5639     VerifyOrQuit(srvCallback->GetNext() == nullptr);
5640 
5641     sSrvCallbacks.Clear();
5642 
5643     AdvanceTime(15 * 1000);
5644 
5645     dnsMsg = sDnsMessages.GetHead();
5646 
5647     for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; queryCount++)
5648     {
5649         VerifyOrQuit(dnsMsg != nullptr);
5650         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5651         dnsMsg->ValidateAsQueryFor(resolver);
5652         dnsMsg = dnsMsg->GetNext();
5653     }
5654 
5655     VerifyOrQuit(dnsMsg == nullptr);
5656 
5657     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5658 
5659     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
5660     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
5661 
5662     Log("End of test");
5663 
5664     testFreeInstance(sInstance);
5665 }
5666 
TestTxtResolver(void)5667 void TestTxtResolver(void)
5668 {
5669     Core              *mdns = InitTest();
5670     Core::TxtResolver  resolver;
5671     Core::TxtResolver  resolver2;
5672     const DnsMessage  *dnsMsg;
5673     const TxtCallback *txtCallback;
5674     uint16_t           heapAllocations;
5675 
5676     Log("-------------------------------------------------------------------------------------------");
5677     Log("TestTxtResolver");
5678 
5679     AdvanceTime(1);
5680 
5681     heapAllocations = sHeapAllocatedPtrs.GetLength();
5682     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
5683 
5684     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5685     Log("Start a TXT resolver. Validate initial queries.");
5686 
5687     ClearAllBytes(resolver);
5688 
5689     resolver.mServiceInstance = "mysrv";
5690     resolver.mServiceType     = "_srv._udp";
5691     resolver.mInfraIfIndex    = kInfraIfIndex;
5692     resolver.mCallback        = HandleTxtResult;
5693 
5694     sDnsMessages.Clear();
5695     SuccessOrQuit(mdns->StartTxtResolver(resolver));
5696 
5697     for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; queryCount++)
5698     {
5699         sDnsMessages.Clear();
5700 
5701         AdvanceTime((queryCount == 0) ? 125 : (1U << (queryCount - 1)) * 1000);
5702 
5703         VerifyOrQuit(!sDnsMessages.IsEmpty());
5704         dnsMsg = sDnsMessages.GetHead();
5705         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5706         dnsMsg->ValidateAsQueryFor(resolver);
5707         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5708     }
5709 
5710     sDnsMessages.Clear();
5711 
5712     AdvanceTime(20 * 1000);
5713     VerifyOrQuit(sDnsMessages.IsEmpty());
5714 
5715     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5716     Log("Send a response. Validate callback result.");
5717 
5718     sTxtCallbacks.Clear();
5719 
5720     SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
5721 
5722     AdvanceTime(1);
5723 
5724     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
5725     txtCallback = sTxtCallbacks.GetHead();
5726     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5727     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
5728     VerifyOrQuit(txtCallback->Matches(kTxtData1));
5729     VerifyOrQuit(txtCallback->mTtl == 120);
5730     VerifyOrQuit(txtCallback->GetNext() == nullptr);
5731 
5732     VerifyOrQuit(sDnsMessages.IsEmpty());
5733 
5734     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5735     Log("Send an updated response changing TXT data. Validate callback result.");
5736 
5737     AdvanceTime(1000);
5738 
5739     sTxtCallbacks.Clear();
5740 
5741     SendTxtResponse("mysrv._srv._udp.local.", kTxtData2, sizeof(kTxtData2), 120, kInAnswerSection);
5742 
5743     AdvanceTime(1);
5744 
5745     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
5746     txtCallback = sTxtCallbacks.GetHead();
5747     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5748     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
5749     VerifyOrQuit(txtCallback->Matches(kTxtData2));
5750     VerifyOrQuit(txtCallback->mTtl == 120);
5751     VerifyOrQuit(txtCallback->GetNext() == nullptr);
5752 
5753     VerifyOrQuit(sDnsMessages.IsEmpty());
5754 
5755     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5756     Log("Send an updated response changing TXT data to empty. Validate callback result.");
5757 
5758     AdvanceTime(1000);
5759 
5760     sTxtCallbacks.Clear();
5761 
5762     SendTxtResponse("mysrv._srv._udp.local.", kEmptyTxtData, sizeof(kEmptyTxtData), 120, kInAnswerSection);
5763 
5764     AdvanceTime(1);
5765 
5766     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
5767     txtCallback = sTxtCallbacks.GetHead();
5768     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5769     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
5770     VerifyOrQuit(txtCallback->Matches(kEmptyTxtData));
5771     VerifyOrQuit(txtCallback->mTtl == 120);
5772     VerifyOrQuit(txtCallback->GetNext() == nullptr);
5773 
5774     VerifyOrQuit(sDnsMessages.IsEmpty());
5775 
5776     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5777     Log("Send an updated response changing TTL. Validate callback result.");
5778 
5779     AdvanceTime(1000);
5780 
5781     sTxtCallbacks.Clear();
5782 
5783     SendTxtResponse("mysrv._srv._udp.local.", kEmptyTxtData, sizeof(kEmptyTxtData), 500, kInAnswerSection);
5784 
5785     AdvanceTime(1);
5786 
5787     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
5788     txtCallback = sTxtCallbacks.GetHead();
5789     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5790     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
5791     VerifyOrQuit(txtCallback->Matches(kEmptyTxtData));
5792     VerifyOrQuit(txtCallback->mTtl == 500);
5793     VerifyOrQuit(txtCallback->GetNext() == nullptr);
5794 
5795     VerifyOrQuit(sDnsMessages.IsEmpty());
5796 
5797     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5798     Log("Send an updated response with zero TTL. Validate callback result.");
5799 
5800     AdvanceTime(1000);
5801 
5802     sTxtCallbacks.Clear();
5803 
5804     SendTxtResponse("mysrv._srv._udp.local.", kEmptyTxtData, sizeof(kEmptyTxtData), 0, kInAnswerSection);
5805 
5806     AdvanceTime(1);
5807 
5808     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
5809     txtCallback = sTxtCallbacks.GetHead();
5810     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5811     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
5812     VerifyOrQuit(txtCallback->mTtl == 0);
5813     VerifyOrQuit(txtCallback->GetNext() == nullptr);
5814 
5815     VerifyOrQuit(sDnsMessages.IsEmpty());
5816 
5817     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5818     Log("Send an updated response. Validate callback result.");
5819 
5820     sTxtCallbacks.Clear();
5821     AdvanceTime(100 * 1000);
5822 
5823     SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
5824 
5825     AdvanceTime(1);
5826 
5827     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
5828     txtCallback = sTxtCallbacks.GetHead();
5829     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5830     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
5831     VerifyOrQuit(txtCallback->Matches(kTxtData1));
5832     VerifyOrQuit(txtCallback->mTtl == 120);
5833     VerifyOrQuit(txtCallback->GetNext() == nullptr);
5834 
5835     VerifyOrQuit(sDnsMessages.IsEmpty());
5836 
5837     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5838     Log("Send a response with no changes. Validate callback is not invoked.");
5839 
5840     AdvanceTime(1000);
5841 
5842     sTxtCallbacks.Clear();
5843 
5844     SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
5845 
5846     AdvanceTime(100);
5847 
5848     VerifyOrQuit(sTxtCallbacks.IsEmpty());
5849     VerifyOrQuit(sDnsMessages.IsEmpty());
5850 
5851     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5852     Log("Start another resolver for the same service and different callback. Validate results.");
5853 
5854     resolver2.mServiceInstance = "mysrv";
5855     resolver2.mServiceType     = "_srv._udp";
5856     resolver2.mInfraIfIndex    = kInfraIfIndex;
5857     resolver2.mCallback        = HandleTxtResultAlternate;
5858 
5859     sTxtCallbacks.Clear();
5860 
5861     SuccessOrQuit(mdns->StartTxtResolver(resolver2));
5862 
5863     AdvanceTime(1);
5864 
5865     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
5866     txtCallback = sTxtCallbacks.GetHead();
5867     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5868     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
5869     VerifyOrQuit(txtCallback->Matches(kTxtData1));
5870     VerifyOrQuit(txtCallback->mTtl == 120);
5871     VerifyOrQuit(txtCallback->GetNext() == nullptr);
5872 
5873     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5874     Log("Start same resolver again and check the returned error.");
5875 
5876     sTxtCallbacks.Clear();
5877 
5878     VerifyOrQuit(mdns->StartTxtResolver(resolver2) == kErrorAlready);
5879 
5880     AdvanceTime(5000);
5881 
5882     VerifyOrQuit(sTxtCallbacks.IsEmpty());
5883 
5884     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5885     Log("Check query is sent at 80 percentage of TTL and then respond to it.");
5886 
5887     SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
5888 
5889     // First query should be sent at 80-82% of TTL of 120 second (96.0-98.4 sec).
5890     // We wait for 100 second. Note that 5 seconds already passed in the
5891     // previous step.
5892 
5893     AdvanceTime(96 * 1000 - 1);
5894 
5895     VerifyOrQuit(sDnsMessages.IsEmpty());
5896 
5897     AdvanceTime(4 * 1000 + 1);
5898 
5899     VerifyOrQuit(!sDnsMessages.IsEmpty());
5900     dnsMsg = sDnsMessages.GetHead();
5901     dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5902     dnsMsg->ValidateAsQueryFor(resolver);
5903     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5904 
5905     sDnsMessages.Clear();
5906     VerifyOrQuit(sTxtCallbacks.IsEmpty());
5907 
5908     AdvanceTime(10);
5909 
5910     SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
5911 
5912     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5913     Log("Check queries are sent at 80, 85, 90, 95 percentages of TTL.");
5914 
5915     for (uint8_t queryCount = 0; queryCount < kNumRefreshQueries; queryCount++)
5916     {
5917         if (queryCount == 0)
5918         {
5919             // First query is expected in 80-82% of TTL, so
5920             // 80% of 120 = 96.0, 82% of 120 = 98.4
5921 
5922             AdvanceTime(96 * 1000 - 1);
5923         }
5924         else
5925         {
5926             // Next query should happen within 3%-5% of TTL
5927             // from previous query. We wait 3% of TTL here.
5928             AdvanceTime(3600 - 1);
5929         }
5930 
5931         VerifyOrQuit(sDnsMessages.IsEmpty());
5932 
5933         // Wait for 2% of TTL of 120 which is 2.4 sec.
5934 
5935         AdvanceTime(2400 + 1);
5936 
5937         VerifyOrQuit(!sDnsMessages.IsEmpty());
5938         dnsMsg = sDnsMessages.GetHead();
5939         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
5940         dnsMsg->ValidateAsQueryFor(resolver);
5941         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
5942 
5943         sDnsMessages.Clear();
5944         VerifyOrQuit(sTxtCallbacks.IsEmpty());
5945     }
5946 
5947     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5948     Log("Check TTL timeout and callback result.");
5949 
5950     AdvanceTime(6 * 1000);
5951 
5952     txtCallback = sTxtCallbacks.GetHead();
5953 
5954     for (uint8_t iter = 0; iter < 2; iter++)
5955     {
5956         VerifyOrQuit(txtCallback != nullptr);
5957         VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5958         VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
5959         VerifyOrQuit(txtCallback->mTtl == 0);
5960         txtCallback = txtCallback->GetNext();
5961     }
5962 
5963     VerifyOrQuit(txtCallback == nullptr);
5964 
5965     VerifyOrQuit(sDnsMessages.IsEmpty());
5966 
5967     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5968 
5969     sTxtCallbacks.Clear();
5970     sDnsMessages.Clear();
5971 
5972     AdvanceTime(200 * 1000);
5973 
5974     VerifyOrQuit(sTxtCallbacks.IsEmpty());
5975     VerifyOrQuit(sDnsMessages.IsEmpty());
5976 
5977     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5978     Log("Stop the second resolver");
5979 
5980     sTxtCallbacks.Clear();
5981 
5982     SuccessOrQuit(mdns->StopTxtResolver(resolver2));
5983 
5984     AdvanceTime(100 * 1000);
5985 
5986     VerifyOrQuit(sTxtCallbacks.IsEmpty());
5987     VerifyOrQuit(sDnsMessages.IsEmpty());
5988 
5989     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
5990     Log("Send a new response and make sure result callback is invoked");
5991 
5992     SendTxtResponse("mysrv._srv._udp.local.", kTxtData1, sizeof(kTxtData1), 120, kInAnswerSection);
5993 
5994     AdvanceTime(1);
5995 
5996     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
5997     txtCallback = sTxtCallbacks.GetHead();
5998     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
5999     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
6000     VerifyOrQuit(txtCallback->Matches(kTxtData1));
6001     VerifyOrQuit(txtCallback->mTtl == 120);
6002     VerifyOrQuit(txtCallback->GetNext() == nullptr);
6003 
6004     VerifyOrQuit(sDnsMessages.IsEmpty());
6005 
6006     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6007     Log("Stop the resolver. There is no active resolver. Ensure no queries are sent");
6008 
6009     sTxtCallbacks.Clear();
6010 
6011     SuccessOrQuit(mdns->StopTxtResolver(resolver));
6012 
6013     AdvanceTime(20 * 1000);
6014 
6015     VerifyOrQuit(sTxtCallbacks.IsEmpty());
6016     VerifyOrQuit(sDnsMessages.IsEmpty());
6017 
6018     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6019     Log("Restart the resolver with more than half of TTL remaining.");
6020     Log("Ensure cached entry is reported in the result callback and no queries are sent.");
6021 
6022     SuccessOrQuit(mdns->StartTxtResolver(resolver));
6023 
6024     AdvanceTime(1);
6025 
6026     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
6027     txtCallback = sTxtCallbacks.GetHead();
6028     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
6029     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
6030     VerifyOrQuit(txtCallback->Matches(kTxtData1));
6031     VerifyOrQuit(txtCallback->mTtl == 120);
6032     VerifyOrQuit(txtCallback->GetNext() == nullptr);
6033 
6034     VerifyOrQuit(sDnsMessages.IsEmpty());
6035 
6036     AdvanceTime(20 * 1000);
6037 
6038     VerifyOrQuit(sDnsMessages.IsEmpty());
6039 
6040     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6041     Log("Stop and start the resolver again after less than half TTL remaining.");
6042     Log("Ensure cached entry is still reported in the result callback but queries should be sent");
6043 
6044     sTxtCallbacks.Clear();
6045 
6046     SuccessOrQuit(mdns->StopTxtResolver(resolver));
6047 
6048     AdvanceTime(25 * 1000);
6049 
6050     SuccessOrQuit(mdns->StartTxtResolver(resolver));
6051 
6052     AdvanceTime(1);
6053 
6054     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
6055     txtCallback = sTxtCallbacks.GetHead();
6056     VerifyOrQuit(txtCallback->mServiceInstance.Matches("mysrv"));
6057     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
6058     VerifyOrQuit(txtCallback->Matches(kTxtData1));
6059     VerifyOrQuit(txtCallback->mTtl == 120);
6060     VerifyOrQuit(txtCallback->GetNext() == nullptr);
6061 
6062     sTxtCallbacks.Clear();
6063 
6064     AdvanceTime(15 * 1000);
6065 
6066     dnsMsg = sDnsMessages.GetHead();
6067 
6068     for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; queryCount++)
6069     {
6070         VerifyOrQuit(dnsMsg != nullptr);
6071         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
6072         dnsMsg->ValidateAsQueryFor(resolver);
6073         dnsMsg = dnsMsg->GetNext();
6074     }
6075 
6076     VerifyOrQuit(dnsMsg == nullptr);
6077 
6078     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6079 
6080     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
6081     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
6082 
6083     Log("End of test");
6084 
6085     testFreeInstance(sInstance);
6086 }
6087 
TestIp6AddrResolver(void)6088 void TestIp6AddrResolver(void)
6089 {
6090     Core                 *mdns = InitTest();
6091     Core::AddressResolver resolver;
6092     Core::AddressResolver resolver2;
6093     AddrAndTtl            addrs[5];
6094     const DnsMessage     *dnsMsg;
6095     const AddrCallback   *addrCallback;
6096     uint16_t              heapAllocations;
6097 
6098     Log("-------------------------------------------------------------------------------------------");
6099     Log("TestIp6AddrResolver");
6100 
6101     AdvanceTime(1);
6102 
6103     heapAllocations = sHeapAllocatedPtrs.GetLength();
6104     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
6105 
6106     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6107     Log("Start an IPv6 address resolver. Validate initial queries.");
6108 
6109     ClearAllBytes(resolver);
6110 
6111     resolver.mHostName     = "myhost";
6112     resolver.mInfraIfIndex = kInfraIfIndex;
6113     resolver.mCallback     = HandleAddrResult;
6114 
6115     sDnsMessages.Clear();
6116     SuccessOrQuit(mdns->StartIp6AddressResolver(resolver));
6117 
6118     for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; queryCount++)
6119     {
6120         sDnsMessages.Clear();
6121 
6122         AdvanceTime((queryCount == 0) ? 125 : (1U << (queryCount - 1)) * 1000);
6123 
6124         VerifyOrQuit(!sDnsMessages.IsEmpty());
6125         dnsMsg = sDnsMessages.GetHead();
6126         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
6127         dnsMsg->ValidateAsQueryFor(resolver);
6128         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
6129     }
6130 
6131     sDnsMessages.Clear();
6132 
6133     AdvanceTime(20 * 1000);
6134     VerifyOrQuit(sDnsMessages.IsEmpty());
6135 
6136     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6137     Log("Send a response. Validate callback result.");
6138 
6139     sAddrCallbacks.Clear();
6140 
6141     SuccessOrQuit(addrs[0].mAddress.FromString("fd00::1"));
6142     addrs[0].mTtl = 120;
6143 
6144     SendHostAddrResponse("myhost.local.", addrs, 1, /* aCachFlush */ true, kInAnswerSection);
6145 
6146     AdvanceTime(1);
6147 
6148     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6149     addrCallback = sAddrCallbacks.GetHead();
6150     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6151     VerifyOrQuit(addrCallback->Matches(addrs, 1));
6152     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6153 
6154     VerifyOrQuit(sDnsMessages.IsEmpty());
6155 
6156     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6157     Log("Send an updated response adding a new address. Validate callback result.");
6158 
6159     SuccessOrQuit(addrs[1].mAddress.FromString("fd00::2"));
6160     addrs[1].mTtl = 120;
6161 
6162     AdvanceTime(1000);
6163 
6164     sAddrCallbacks.Clear();
6165 
6166     SendHostAddrResponse("myhost.local.", addrs, 2, /* aCachFlush */ true, kInAnswerSection);
6167 
6168     AdvanceTime(1);
6169 
6170     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6171     addrCallback = sAddrCallbacks.GetHead();
6172     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6173     VerifyOrQuit(addrCallback->Matches(addrs, 2));
6174     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6175 
6176     VerifyOrQuit(sDnsMessages.IsEmpty());
6177 
6178     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6179     Log("Send an updated response adding and removing addresses. Validate callback result.");
6180 
6181     SuccessOrQuit(addrs[0].mAddress.FromString("fd00::2"));
6182     SuccessOrQuit(addrs[1].mAddress.FromString("fd00::aa"));
6183     SuccessOrQuit(addrs[2].mAddress.FromString("fe80::bb"));
6184     addrs[0].mTtl = 120;
6185     addrs[1].mTtl = 120;
6186     addrs[2].mTtl = 120;
6187 
6188     AdvanceTime(1000);
6189 
6190     sAddrCallbacks.Clear();
6191 
6192     SendHostAddrResponse("myhost.local.", addrs, 3, /* aCachFlush */ true, kInAnswerSection);
6193 
6194     AdvanceTime(1);
6195 
6196     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6197     addrCallback = sAddrCallbacks.GetHead();
6198     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6199     VerifyOrQuit(addrCallback->Matches(addrs, 3));
6200     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6201 
6202     VerifyOrQuit(sDnsMessages.IsEmpty());
6203 
6204     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6205     Log("Send a response without cache flush adding an address. Validate callback result.");
6206 
6207     SuccessOrQuit(addrs[3].mAddress.FromString("fd00::3"));
6208     addrs[3].mTtl = 500;
6209 
6210     AdvanceTime(1000);
6211 
6212     sAddrCallbacks.Clear();
6213 
6214     SendHostAddrResponse("myhost.local.", &addrs[3], 1, /* aCachFlush */ false, kInAnswerSection);
6215 
6216     AdvanceTime(1);
6217 
6218     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6219     addrCallback = sAddrCallbacks.GetHead();
6220     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6221     VerifyOrQuit(addrCallback->Matches(addrs, 4));
6222     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6223 
6224     VerifyOrQuit(sDnsMessages.IsEmpty());
6225 
6226     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6227     Log("Send a response without cache flush with existing addresses. Validate that callback is not called.");
6228 
6229     AdvanceTime(1000);
6230 
6231     sAddrCallbacks.Clear();
6232 
6233     SendHostAddrResponse("myhost.local.", &addrs[2], 2, /* aCachFlush */ false, kInAnswerSection);
6234 
6235     AdvanceTime(1);
6236 
6237     VerifyOrQuit(sAddrCallbacks.IsEmpty());
6238     VerifyOrQuit(sDnsMessages.IsEmpty());
6239 
6240     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6241     Log("Send a response without no changes to the list. Validate that callback is not called");
6242 
6243     AdvanceTime(1000);
6244 
6245     sAddrCallbacks.Clear();
6246 
6247     SendHostAddrResponse("myhost.local.", addrs, 4, /* aCachFlush */ true, kInAdditionalSection);
6248 
6249     AdvanceTime(1);
6250 
6251     VerifyOrQuit(sAddrCallbacks.IsEmpty());
6252     VerifyOrQuit(sDnsMessages.IsEmpty());
6253 
6254     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6255     Log("Send a response without cache flush updating TTL of existing address. Validate callback result.");
6256 
6257     addrs[3].mTtl = 200;
6258 
6259     AdvanceTime(1000);
6260 
6261     sAddrCallbacks.Clear();
6262 
6263     SendHostAddrResponse("myhost.local.", &addrs[3], 1, /* aCachFlush */ false, kInAnswerSection);
6264 
6265     AdvanceTime(1);
6266 
6267     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6268     addrCallback = sAddrCallbacks.GetHead();
6269     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6270     VerifyOrQuit(addrCallback->Matches(addrs, 4));
6271     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6272 
6273     VerifyOrQuit(sDnsMessages.IsEmpty());
6274 
6275     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6276     Log("Send a response without cache flush removing an address (zero TTL). Validate callback result.");
6277 
6278     addrs[3].mTtl = 0;
6279 
6280     AdvanceTime(1000);
6281 
6282     sAddrCallbacks.Clear();
6283 
6284     SendHostAddrResponse("myhost.local.", &addrs[3], 1, /* aCachFlush */ false, kInAnswerSection);
6285 
6286     AdvanceTime(1);
6287 
6288     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6289     addrCallback = sAddrCallbacks.GetHead();
6290     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6291     VerifyOrQuit(addrCallback->Matches(addrs, 3));
6292     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6293 
6294     VerifyOrQuit(sDnsMessages.IsEmpty());
6295 
6296     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6297     Log("Send a response with cache flush removing all addresses. Validate callback result.");
6298 
6299     addrs[0].mTtl = 0;
6300 
6301     AdvanceTime(1000);
6302 
6303     sAddrCallbacks.Clear();
6304 
6305     SendHostAddrResponse("myhost.local.", addrs, 1, /* aCachFlush */ true, kInAnswerSection);
6306 
6307     AdvanceTime(1);
6308 
6309     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6310     addrCallback = sAddrCallbacks.GetHead();
6311     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6312     VerifyOrQuit(addrCallback->Matches(addrs, 0));
6313     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6314 
6315     VerifyOrQuit(sDnsMessages.IsEmpty());
6316 
6317     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6318     Log("Send a response with addresses with different TTL. Validate callback result");
6319 
6320     SuccessOrQuit(addrs[0].mAddress.FromString("fd00::00"));
6321     SuccessOrQuit(addrs[1].mAddress.FromString("fd00::11"));
6322     SuccessOrQuit(addrs[2].mAddress.FromString("fe80::22"));
6323     SuccessOrQuit(addrs[3].mAddress.FromString("fe80::33"));
6324     addrs[0].mTtl = 120;
6325     addrs[1].mTtl = 800;
6326     addrs[2].mTtl = 2000;
6327     addrs[3].mTtl = 8000;
6328 
6329     AdvanceTime(5 * 1000);
6330 
6331     sAddrCallbacks.Clear();
6332 
6333     SendHostAddrResponse("myhost.local.", addrs, 4, /* aCachFlush */ true, kInAnswerSection);
6334 
6335     AdvanceTime(1);
6336 
6337     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6338     addrCallback = sAddrCallbacks.GetHead();
6339     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6340     VerifyOrQuit(addrCallback->Matches(addrs, 4));
6341     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6342 
6343     VerifyOrQuit(sDnsMessages.IsEmpty());
6344 
6345     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6346     Log("Start another resolver for the same host and different callback. Validate results.");
6347 
6348     resolver2.mHostName     = "myhost";
6349     resolver2.mInfraIfIndex = kInfraIfIndex;
6350     resolver2.mCallback     = HandleAddrResultAlternate;
6351 
6352     sAddrCallbacks.Clear();
6353 
6354     SuccessOrQuit(mdns->StartIp6AddressResolver(resolver2));
6355 
6356     AdvanceTime(1);
6357 
6358     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6359     addrCallback = sAddrCallbacks.GetHead();
6360     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6361     VerifyOrQuit(addrCallback->Matches(addrs, 4));
6362     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6363 
6364     VerifyOrQuit(sDnsMessages.IsEmpty());
6365 
6366     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6367     Log("Start same resolver again and check the returned error.");
6368 
6369     sAddrCallbacks.Clear();
6370 
6371     VerifyOrQuit(mdns->StartIp6AddressResolver(resolver2) == kErrorAlready);
6372 
6373     AdvanceTime(5000);
6374 
6375     VerifyOrQuit(sAddrCallbacks.IsEmpty());
6376     sDnsMessages.Clear();
6377 
6378     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6379     Log("Check query is sent at 80 percentage of TTL and then respond to it.");
6380 
6381     SendHostAddrResponse("myhost.local.", addrs, 4, /* aCachFlush */ true, kInAnswerSection);
6382 
6383     // First query should be sent at 80-82% of TTL of 120 second (96.0-98.4 sec).
6384     // We wait for 100 second. Note that 5 seconds already passed in the
6385     // previous step.
6386 
6387     AdvanceTime(96 * 1000 - 1);
6388 
6389     VerifyOrQuit(sDnsMessages.IsEmpty());
6390 
6391     AdvanceTime(4 * 1000 + 1);
6392 
6393     VerifyOrQuit(!sDnsMessages.IsEmpty());
6394     dnsMsg = sDnsMessages.GetHead();
6395     dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
6396     dnsMsg->ValidateAsQueryFor(resolver);
6397     VerifyOrQuit(dnsMsg->GetNext() == nullptr);
6398 
6399     sDnsMessages.Clear();
6400     VerifyOrQuit(sAddrCallbacks.IsEmpty());
6401 
6402     AdvanceTime(10);
6403 
6404     SendHostAddrResponse("myhost.local.", addrs, 4, /* aCachFlush */ true, kInAnswerSection);
6405 
6406     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6407     Log("Check queries are sent at 80, 85, 90, 95 percentages of TTL.");
6408 
6409     for (uint8_t queryCount = 0; queryCount < kNumRefreshQueries; queryCount++)
6410     {
6411         if (queryCount == 0)
6412         {
6413             // First query is expected in 80-82% of TTL, so
6414             // 80% of 120 = 96.0, 82% of 120 = 98.4
6415 
6416             AdvanceTime(96 * 1000 - 1);
6417         }
6418         else
6419         {
6420             // Next query should happen within 3%-5% of TTL
6421             // from previous query. We wait 3% of TTL here.
6422             AdvanceTime(3600 - 1);
6423         }
6424 
6425         VerifyOrQuit(sDnsMessages.IsEmpty());
6426 
6427         // Wait for 2% of TTL of 120 which is 2.4 sec.
6428 
6429         AdvanceTime(2400 + 1);
6430 
6431         VerifyOrQuit(!sDnsMessages.IsEmpty());
6432         dnsMsg = sDnsMessages.GetHead();
6433         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
6434         dnsMsg->ValidateAsQueryFor(resolver);
6435         VerifyOrQuit(dnsMsg->GetNext() == nullptr);
6436 
6437         sDnsMessages.Clear();
6438         VerifyOrQuit(sAddrCallbacks.IsEmpty());
6439     }
6440 
6441     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6442     Log("Check TTL timeout of first address (TTL 120) and callback result.");
6443 
6444     AdvanceTime(6 * 1000);
6445 
6446     addrCallback = sAddrCallbacks.GetHead();
6447 
6448     for (uint8_t iter = 0; iter < 2; iter++)
6449     {
6450         VerifyOrQuit(addrCallback != nullptr);
6451         VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6452         VerifyOrQuit(addrCallback->Matches(&addrs[1], 3));
6453         addrCallback = addrCallback->GetNext();
6454     }
6455 
6456     VerifyOrQuit(addrCallback == nullptr);
6457 
6458     VerifyOrQuit(sDnsMessages.IsEmpty());
6459 
6460     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6461     Log("Check TTL timeout of next address (TTL 800) and callback result.");
6462 
6463     sAddrCallbacks.Clear();
6464 
6465     AdvanceTime((800 - 120) * 1000);
6466 
6467     addrCallback = sAddrCallbacks.GetHead();
6468 
6469     for (uint8_t iter = 0; iter < 2; iter++)
6470     {
6471         VerifyOrQuit(addrCallback != nullptr);
6472         VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6473         VerifyOrQuit(addrCallback->Matches(&addrs[2], 2));
6474         addrCallback = addrCallback->GetNext();
6475     }
6476 
6477     VerifyOrQuit(addrCallback == nullptr);
6478 
6479     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6480 
6481     sAddrCallbacks.Clear();
6482     sDnsMessages.Clear();
6483 
6484     AdvanceTime(200 * 1000);
6485 
6486     VerifyOrQuit(sAddrCallbacks.IsEmpty());
6487     VerifyOrQuit(sDnsMessages.IsEmpty());
6488 
6489     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6490     Log("Stop the second resolver");
6491 
6492     sAddrCallbacks.Clear();
6493 
6494     SuccessOrQuit(mdns->StopIp6AddressResolver(resolver2));
6495 
6496     AdvanceTime(100 * 1000);
6497 
6498     VerifyOrQuit(sAddrCallbacks.IsEmpty());
6499     VerifyOrQuit(sDnsMessages.IsEmpty());
6500 
6501     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6502     Log("Send a new response and make sure result callback is invoked");
6503 
6504     sAddrCallbacks.Clear();
6505 
6506     SendHostAddrResponse("myhost.local.", addrs, 1, /* aCachFlush */ true, kInAnswerSection);
6507 
6508     AdvanceTime(1);
6509 
6510     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6511     addrCallback = sAddrCallbacks.GetHead();
6512     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6513     VerifyOrQuit(addrCallback->Matches(addrs, 1));
6514     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6515 
6516     VerifyOrQuit(sDnsMessages.IsEmpty());
6517 
6518     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6519     Log("Stop the resolver. There is no active resolver. Ensure no queries are sent");
6520 
6521     sAddrCallbacks.Clear();
6522 
6523     SuccessOrQuit(mdns->StopIp6AddressResolver(resolver));
6524 
6525     AdvanceTime(20 * 1000);
6526 
6527     VerifyOrQuit(sAddrCallbacks.IsEmpty());
6528     VerifyOrQuit(sDnsMessages.IsEmpty());
6529 
6530     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6531     Log("Restart the resolver with more than half of TTL remaining.");
6532     Log("Ensure cached entry is reported in the result callback and no queries are sent.");
6533 
6534     SuccessOrQuit(mdns->StartIp6AddressResolver(resolver));
6535 
6536     AdvanceTime(1);
6537 
6538     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6539     addrCallback = sAddrCallbacks.GetHead();
6540     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6541     VerifyOrQuit(addrCallback->Matches(addrs, 1));
6542     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6543 
6544     VerifyOrQuit(sDnsMessages.IsEmpty());
6545 
6546     AdvanceTime(20 * 1000);
6547 
6548     VerifyOrQuit(sDnsMessages.IsEmpty());
6549 
6550     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6551     Log("Stop and start the resolver again after less than half TTL remaining.");
6552     Log("Ensure cached entry is still reported in the result callback but queries should be sent");
6553 
6554     sAddrCallbacks.Clear();
6555 
6556     SuccessOrQuit(mdns->StopIp6AddressResolver(resolver));
6557 
6558     AdvanceTime(25 * 1000);
6559 
6560     SuccessOrQuit(mdns->StartIp6AddressResolver(resolver));
6561 
6562     AdvanceTime(1);
6563 
6564     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6565     addrCallback = sAddrCallbacks.GetHead();
6566     VerifyOrQuit(addrCallback->mHostName.Matches("myhost"));
6567     VerifyOrQuit(addrCallback->Matches(addrs, 1));
6568     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6569 
6570     sAddrCallbacks.Clear();
6571 
6572     AdvanceTime(15 * 1000);
6573 
6574     dnsMsg = sDnsMessages.GetHead();
6575 
6576     for (uint8_t queryCount = 0; queryCount < kNumInitalQueries; queryCount++)
6577     {
6578         VerifyOrQuit(dnsMsg != nullptr);
6579         dnsMsg->ValidateHeader(kMulticastQuery, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 0);
6580         dnsMsg->ValidateAsQueryFor(resolver);
6581         dnsMsg = dnsMsg->GetNext();
6582     }
6583 
6584     VerifyOrQuit(dnsMsg == nullptr);
6585 
6586     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6587 
6588     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
6589     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
6590 
6591     Log("End of test");
6592 
6593     testFreeInstance(sInstance);
6594 }
6595 
TestPassiveCache(void)6596 void TestPassiveCache(void)
6597 {
6598     static const char *const kSubTypes[] = {"_sub1", "_xyzw"};
6599 
6600     Core                 *mdns = InitTest();
6601     Core::Browser         browser;
6602     Core::SrvResolver     srvResolver;
6603     Core::TxtResolver     txtResolver;
6604     Core::AddressResolver addrResolver;
6605     Core::Host            host1;
6606     Core::Host            host2;
6607     Core::Service         service1;
6608     Core::Service         service2;
6609     Core::Service         service3;
6610     Ip6::Address          host1Addresses[3];
6611     Ip6::Address          host2Addresses[2];
6612     AddrAndTtl            host1AddrTtls[3];
6613     AddrAndTtl            host2AddrTtls[2];
6614     const DnsMessage     *dnsMsg;
6615     BrowseCallback       *browseCallback;
6616     SrvCallback          *srvCallback;
6617     TxtCallback          *txtCallback;
6618     AddrCallback         *addrCallback;
6619     uint16_t              heapAllocations;
6620 
6621     Log("-------------------------------------------------------------------------------------------");
6622     Log("TestPassiveCache");
6623 
6624     AdvanceTime(1);
6625 
6626     heapAllocations = sHeapAllocatedPtrs.GetLength();
6627     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
6628 
6629     SuccessOrQuit(host1Addresses[0].FromString("fd00::1:aaaa"));
6630     SuccessOrQuit(host1Addresses[1].FromString("fd00::1:bbbb"));
6631     SuccessOrQuit(host1Addresses[2].FromString("fd00::1:cccc"));
6632     host1.mHostName        = "host1";
6633     host1.mAddresses       = host1Addresses;
6634     host1.mAddressesLength = 3;
6635     host1.mTtl             = 1500;
6636 
6637     host1AddrTtls[0].mAddress = host1Addresses[0];
6638     host1AddrTtls[1].mAddress = host1Addresses[1];
6639     host1AddrTtls[2].mAddress = host1Addresses[2];
6640     host1AddrTtls[0].mTtl     = host1.mTtl;
6641     host1AddrTtls[1].mTtl     = host1.mTtl;
6642     host1AddrTtls[2].mTtl     = host1.mTtl;
6643 
6644     SuccessOrQuit(host2Addresses[0].FromString("fd00::2:eeee"));
6645     SuccessOrQuit(host2Addresses[1].FromString("fd00::2:ffff"));
6646     host2.mHostName        = "host2";
6647     host2.mAddresses       = host2Addresses;
6648     host2.mAddressesLength = 2;
6649     host2.mTtl             = 1500;
6650 
6651     host2AddrTtls[0].mAddress = host2Addresses[0];
6652     host2AddrTtls[1].mAddress = host2Addresses[1];
6653     host2AddrTtls[0].mTtl     = host2.mTtl;
6654     host2AddrTtls[1].mTtl     = host2.mTtl;
6655 
6656     service1.mHostName            = host1.mHostName;
6657     service1.mServiceInstance     = "srv1";
6658     service1.mServiceType         = "_srv._udp";
6659     service1.mSubTypeLabels       = kSubTypes;
6660     service1.mSubTypeLabelsLength = 2;
6661     service1.mTxtData             = kTxtData1;
6662     service1.mTxtDataLength       = sizeof(kTxtData1);
6663     service1.mPort                = 1111;
6664     service1.mPriority            = 0;
6665     service1.mWeight              = 0;
6666     service1.mTtl                 = 1500;
6667 
6668     service2.mHostName            = host1.mHostName;
6669     service2.mServiceInstance     = "srv2";
6670     service2.mServiceType         = "_tst._tcp";
6671     service2.mSubTypeLabels       = nullptr;
6672     service2.mSubTypeLabelsLength = 0;
6673     service2.mTxtData             = nullptr;
6674     service2.mTxtDataLength       = 0;
6675     service2.mPort                = 2222;
6676     service2.mPriority            = 2;
6677     service2.mWeight              = 2;
6678     service2.mTtl                 = 1500;
6679 
6680     service3.mHostName            = host2.mHostName;
6681     service3.mServiceInstance     = "srv3";
6682     service3.mServiceType         = "_srv._udp";
6683     service3.mSubTypeLabels       = kSubTypes;
6684     service3.mSubTypeLabelsLength = 1;
6685     service3.mTxtData             = kTxtData2;
6686     service3.mTxtDataLength       = sizeof(kTxtData2);
6687     service3.mPort                = 3333;
6688     service3.mPriority            = 3;
6689     service3.mWeight              = 3;
6690     service3.mTtl                 = 1500;
6691 
6692     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6693     Log("Register 2 hosts and 3 services");
6694 
6695     SuccessOrQuit(mdns->RegisterHost(host1, 0, HandleSuccessCallback));
6696     SuccessOrQuit(mdns->RegisterHost(host2, 1, HandleSuccessCallback));
6697     SuccessOrQuit(mdns->RegisterService(service1, 2, HandleSuccessCallback));
6698     SuccessOrQuit(mdns->RegisterService(service2, 3, HandleSuccessCallback));
6699     SuccessOrQuit(mdns->RegisterService(service3, 4, HandleSuccessCallback));
6700 
6701     AdvanceTime(10 * 1000);
6702 
6703     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6704     Log("Start a browser for `_srv._udp`, validate callback result");
6705 
6706     browser.mServiceType  = "_srv._udp";
6707     browser.mSubTypeLabel = nullptr;
6708     browser.mInfraIfIndex = kInfraIfIndex;
6709     browser.mCallback     = HandleBrowseResult;
6710 
6711     sBrowseCallbacks.Clear();
6712 
6713     SuccessOrQuit(mdns->StartBrowser(browser));
6714 
6715     AdvanceTime(350);
6716 
6717     browseCallback = sBrowseCallbacks.GetHead();
6718 
6719     for (uint8_t iter = 0; iter < 2; iter++)
6720     {
6721         VerifyOrQuit(browseCallback != nullptr);
6722 
6723         VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
6724         VerifyOrQuit(!browseCallback->mIsSubType);
6725         VerifyOrQuit(browseCallback->mServiceInstance.Matches("srv1") ||
6726                      browseCallback->mServiceInstance.Matches("srv3"));
6727         VerifyOrQuit(browseCallback->mTtl == 1500);
6728 
6729         browseCallback = browseCallback->GetNext();
6730     }
6731 
6732     VerifyOrQuit(browseCallback == nullptr);
6733 
6734     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6735     Log("Start SRV and TXT resolvers for the srv1 and for its host name.");
6736     Log("Ensure all results are immediately provided from cache.");
6737 
6738     srvResolver.mServiceInstance = "srv1";
6739     srvResolver.mServiceType     = "_srv._udp";
6740     srvResolver.mInfraIfIndex    = kInfraIfIndex;
6741     srvResolver.mCallback        = HandleSrvResult;
6742 
6743     txtResolver.mServiceInstance = "srv1";
6744     txtResolver.mServiceType     = "_srv._udp";
6745     txtResolver.mInfraIfIndex    = kInfraIfIndex;
6746     txtResolver.mCallback        = HandleTxtResult;
6747 
6748     addrResolver.mHostName     = "host1";
6749     addrResolver.mInfraIfIndex = kInfraIfIndex;
6750     addrResolver.mCallback     = HandleAddrResult;
6751 
6752     sSrvCallbacks.Clear();
6753     sTxtCallbacks.Clear();
6754     sAddrCallbacks.Clear();
6755     sDnsMessages.Clear();
6756 
6757     SuccessOrQuit(mdns->StartSrvResolver(srvResolver));
6758     SuccessOrQuit(mdns->StartTxtResolver(txtResolver));
6759     SuccessOrQuit(mdns->StartIp6AddressResolver(addrResolver));
6760 
6761     AdvanceTime(1);
6762 
6763     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
6764     srvCallback = sSrvCallbacks.GetHead();
6765     VerifyOrQuit(srvCallback->mServiceInstance.Matches("srv1"));
6766     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
6767     VerifyOrQuit(srvCallback->mHostName.Matches("host1"));
6768     VerifyOrQuit(srvCallback->mPort == 1111);
6769     VerifyOrQuit(srvCallback->mPriority == 0);
6770     VerifyOrQuit(srvCallback->mWeight == 0);
6771     VerifyOrQuit(srvCallback->mTtl == 1500);
6772     VerifyOrQuit(srvCallback->GetNext() == nullptr);
6773 
6774     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
6775     txtCallback = sTxtCallbacks.GetHead();
6776     VerifyOrQuit(txtCallback->mServiceInstance.Matches("srv1"));
6777     VerifyOrQuit(txtCallback->mServiceType.Matches("_srv._udp"));
6778     VerifyOrQuit(txtCallback->Matches(kTxtData1));
6779     VerifyOrQuit(txtCallback->mTtl == 1500);
6780     VerifyOrQuit(txtCallback->GetNext() == nullptr);
6781 
6782     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6783     addrCallback = sAddrCallbacks.GetHead();
6784     VerifyOrQuit(addrCallback->mHostName.Matches("host1"));
6785     VerifyOrQuit(addrCallback->Matches(host1AddrTtls, 3));
6786     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6787 
6788     AdvanceTime(400);
6789 
6790     VerifyOrQuit(sDnsMessages.IsEmpty());
6791 
6792     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6793     Log("Start a browser for sub-type service, validate callback result");
6794 
6795     browser.mServiceType  = "_srv._udp";
6796     browser.mSubTypeLabel = "_xyzw";
6797     browser.mInfraIfIndex = kInfraIfIndex;
6798     browser.mCallback     = HandleBrowseResult;
6799 
6800     sBrowseCallbacks.Clear();
6801 
6802     SuccessOrQuit(mdns->StartBrowser(browser));
6803 
6804     AdvanceTime(350);
6805 
6806     browseCallback = sBrowseCallbacks.GetHead();
6807     VerifyOrQuit(browseCallback != nullptr);
6808 
6809     VerifyOrQuit(browseCallback->mServiceType.Matches("_srv._udp"));
6810     VerifyOrQuit(browseCallback->mIsSubType);
6811     VerifyOrQuit(browseCallback->mSubTypeLabel.Matches("_xyzw"));
6812     VerifyOrQuit(browseCallback->mServiceInstance.Matches("srv1"));
6813     VerifyOrQuit(browseCallback->mTtl == 1500);
6814     VerifyOrQuit(browseCallback->GetNext() == nullptr);
6815 
6816     AdvanceTime(5 * 1000);
6817 
6818     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6819     Log("Start SRV and TXT resolvers for `srv2._tst._tcp` service and validate callback result");
6820 
6821     srvResolver.mServiceInstance = "srv2";
6822     srvResolver.mServiceType     = "_tst._tcp";
6823     srvResolver.mInfraIfIndex    = kInfraIfIndex;
6824     srvResolver.mCallback        = HandleSrvResult;
6825 
6826     txtResolver.mServiceInstance = "srv2";
6827     txtResolver.mServiceType     = "_tst._tcp";
6828     txtResolver.mInfraIfIndex    = kInfraIfIndex;
6829     txtResolver.mCallback        = HandleTxtResult;
6830 
6831     sSrvCallbacks.Clear();
6832     sTxtCallbacks.Clear();
6833 
6834     SuccessOrQuit(mdns->StartSrvResolver(srvResolver));
6835     SuccessOrQuit(mdns->StartTxtResolver(txtResolver));
6836 
6837     AdvanceTime(350);
6838 
6839     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
6840     srvCallback = sSrvCallbacks.GetHead();
6841     VerifyOrQuit(srvCallback->mServiceInstance.Matches("srv2"));
6842     VerifyOrQuit(srvCallback->mServiceType.Matches("_tst._tcp"));
6843     VerifyOrQuit(srvCallback->mHostName.Matches("host1"));
6844     VerifyOrQuit(srvCallback->mPort == 2222);
6845     VerifyOrQuit(srvCallback->mPriority == 2);
6846     VerifyOrQuit(srvCallback->mWeight == 2);
6847     VerifyOrQuit(srvCallback->mTtl == 1500);
6848     VerifyOrQuit(srvCallback->GetNext() == nullptr);
6849 
6850     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
6851     txtCallback = sTxtCallbacks.GetHead();
6852     VerifyOrQuit(txtCallback->mServiceInstance.Matches("srv2"));
6853     VerifyOrQuit(txtCallback->mServiceType.Matches("_tst._tcp"));
6854     VerifyOrQuit(txtCallback->Matches(kEmptyTxtData));
6855     VerifyOrQuit(txtCallback->mTtl == 1500);
6856     VerifyOrQuit(txtCallback->GetNext() == nullptr);
6857 
6858     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6859     Log("Unregister `srv2._tst._tcp` and validate callback results");
6860 
6861     sSrvCallbacks.Clear();
6862     sTxtCallbacks.Clear();
6863 
6864     SuccessOrQuit(mdns->UnregisterService(service2));
6865 
6866     AdvanceTime(350);
6867 
6868     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
6869     srvCallback = sSrvCallbacks.GetHead();
6870     VerifyOrQuit(srvCallback->mServiceInstance.Matches("srv2"));
6871     VerifyOrQuit(srvCallback->mServiceType.Matches("_tst._tcp"));
6872     VerifyOrQuit(srvCallback->mTtl == 0);
6873     VerifyOrQuit(srvCallback->GetNext() == nullptr);
6874 
6875     VerifyOrQuit(!sTxtCallbacks.IsEmpty());
6876     txtCallback = sTxtCallbacks.GetHead();
6877     VerifyOrQuit(txtCallback->mServiceInstance.Matches("srv2"));
6878     VerifyOrQuit(txtCallback->mServiceType.Matches("_tst._tcp"));
6879     VerifyOrQuit(txtCallback->mTtl == 0);
6880     VerifyOrQuit(txtCallback->GetNext() == nullptr);
6881 
6882     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6883     Log("Start an SRV resolver for `srv3._srv._udp` service and validate callback result");
6884 
6885     srvResolver.mServiceInstance = "srv3";
6886     srvResolver.mServiceType     = "_srv._udp";
6887     srvResolver.mInfraIfIndex    = kInfraIfIndex;
6888     srvResolver.mCallback        = HandleSrvResult;
6889 
6890     sSrvCallbacks.Clear();
6891 
6892     SuccessOrQuit(mdns->StartSrvResolver(srvResolver));
6893 
6894     AdvanceTime(350);
6895 
6896     VerifyOrQuit(!sSrvCallbacks.IsEmpty());
6897     srvCallback = sSrvCallbacks.GetHead();
6898     VerifyOrQuit(srvCallback->mServiceInstance.Matches("srv3"));
6899     VerifyOrQuit(srvCallback->mServiceType.Matches("_srv._udp"));
6900     VerifyOrQuit(srvCallback->mHostName.Matches("host2"));
6901     VerifyOrQuit(srvCallback->mPort == 3333);
6902     VerifyOrQuit(srvCallback->mPriority == 3);
6903     VerifyOrQuit(srvCallback->mWeight == 3);
6904     VerifyOrQuit(srvCallback->mTtl == 1500);
6905     VerifyOrQuit(srvCallback->GetNext() == nullptr);
6906 
6907     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6908     Log("Start an address resolver for host2 and validate result is immediately reported from cache");
6909 
6910     addrResolver.mHostName     = "host2";
6911     addrResolver.mInfraIfIndex = kInfraIfIndex;
6912     addrResolver.mCallback     = HandleAddrResult;
6913 
6914     sAddrCallbacks.Clear();
6915     SuccessOrQuit(mdns->StartIp6AddressResolver(addrResolver));
6916 
6917     AdvanceTime(1);
6918 
6919     VerifyOrQuit(!sAddrCallbacks.IsEmpty());
6920     addrCallback = sAddrCallbacks.GetHead();
6921     VerifyOrQuit(addrCallback->mHostName.Matches("host2"));
6922     VerifyOrQuit(addrCallback->Matches(host2AddrTtls, 2));
6923     VerifyOrQuit(addrCallback->GetNext() == nullptr);
6924 
6925     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6926 
6927     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
6928     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
6929 
6930     Log("End of test");
6931 
6932     testFreeInstance(sInstance);
6933 }
6934 
TestLegacyUnicastResponse(void)6935 void TestLegacyUnicastResponse(void)
6936 {
6937     Core             *mdns = InitTest();
6938     Core::Host        host;
6939     Core::Service     service;
6940     const DnsMessage *dnsMsg;
6941     uint16_t          heapAllocations;
6942     DnsNameString     fullServiceName;
6943     DnsNameString     fullServiceType;
6944     DnsNameString     hostFullName;
6945     Ip6::Address      hostAddresses[2];
6946 
6947     Log("-------------------------------------------------------------------------------------------");
6948     Log("TestLegacyUnicastResponse");
6949 
6950     AdvanceTime(1);
6951 
6952     heapAllocations = sHeapAllocatedPtrs.GetLength();
6953     SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
6954 
6955     SuccessOrQuit(hostAddresses[0].FromString("fd00::1:aaaa"));
6956     SuccessOrQuit(hostAddresses[1].FromString("fd00::1:bbbb"));
6957     host.mHostName        = "host";
6958     host.mAddresses       = hostAddresses;
6959     host.mAddressesLength = 2;
6960     host.mTtl             = 1500;
6961     hostFullName.Append("%s.local.", host.mHostName);
6962 
6963     service.mHostName            = host.mHostName;
6964     service.mServiceInstance     = "myservice";
6965     service.mServiceType         = "_srv._udp";
6966     service.mSubTypeLabels       = nullptr;
6967     service.mSubTypeLabelsLength = 0;
6968     service.mTxtData             = kTxtData1;
6969     service.mTxtDataLength       = sizeof(kTxtData1);
6970     service.mPort                = 1234;
6971     service.mPriority            = 1;
6972     service.mWeight              = 2;
6973     service.mTtl                 = 1000;
6974 
6975     fullServiceName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
6976     fullServiceType.Append("%s.local.", service.mServiceType);
6977 
6978     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6979 
6980     sDnsMessages.Clear();
6981 
6982     for (RegCallback &regCallbck : sRegCallbacks)
6983     {
6984         regCallbck.Reset();
6985     }
6986 
6987     SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
6988     SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
6989 
6990     AdvanceTime(10 * 1000);
6991 
6992     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
6993     Log("Send a query with two questions (SRV for service1 and AAAA for host). Validate that no response is sent");
6994 
6995     AdvanceTime(2000);
6996 
6997     sDnsMessages.Clear();
6998     SendQueryForTwo(fullServiceName.AsCString(), ResourceRecord::kTypeSrv, hostFullName.AsCString(),
6999                     ResourceRecord::kTypeAaaa, /* aIsLegacyUnicast */ true);
7000 
7001     AdvanceTime(200);
7002 
7003     dnsMsg = sDnsMessages.GetHead();
7004     VerifyOrQuit(dnsMsg == nullptr);
7005 
7006     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7007     Log("Send a query for SRV record and validate the response");
7008 
7009     AdvanceTime(2000);
7010 
7011     sDnsMessages.Clear();
7012     SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeSrv, ResourceRecord::kClassInternet,
7013               /* aTruncated */ false,
7014               /* aLegacyUnicastQuery */ true);
7015 
7016     AdvanceTime(1000);
7017 
7018     dnsMsg = sDnsMessages.GetHead();
7019     VerifyOrQuit(dnsMsg != nullptr);
7020     dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 3);
7021     dnsMsg->Validate(service, kInAnswerSection, kCheckSrv);
7022     dnsMsg->Validate(host, kInAdditionalSection);
7023 
7024     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7025     Log("Send a query for TXT record and validate the response");
7026 
7027     AdvanceTime(2000);
7028 
7029     sDnsMessages.Clear();
7030     SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeTxt, ResourceRecord::kClassInternet,
7031               /* aTruncated */ false,
7032               /* aLegacyUnicastQuery */ true);
7033 
7034     AdvanceTime(1000);
7035 
7036     dnsMsg = sDnsMessages.GetHead();
7037     VerifyOrQuit(dnsMsg != nullptr);
7038     dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
7039     dnsMsg->Validate(service, kInAnswerSection, kCheckTxt);
7040 
7041     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7042     Log("Send a query for ANY record and validate the response");
7043 
7044     AdvanceTime(2000);
7045 
7046     sDnsMessages.Clear();
7047     SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeAny, ResourceRecord::kClassInternet,
7048               /* aTruncated */ false,
7049               /* aLegacyUnicastQuery */ true);
7050 
7051     AdvanceTime(1000);
7052 
7053     dnsMsg = sDnsMessages.GetHead();
7054     VerifyOrQuit(dnsMsg != nullptr);
7055     dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 3);
7056     dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt);
7057     dnsMsg->Validate(host, kInAdditionalSection);
7058 
7059     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7060     Log("Send a query for PTR record for service type and validate the response");
7061 
7062     AdvanceTime(2000);
7063 
7064     sDnsMessages.Clear();
7065     SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
7066               /* aTruncated */ false,
7067               /* aLegacyUnicastQuery */ true);
7068 
7069     AdvanceTime(1000);
7070 
7071     dnsMsg = sDnsMessages.GetHead();
7072     VerifyOrQuit(dnsMsg != nullptr);
7073     dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 4);
7074     dnsMsg->Validate(service, kInAnswerSection, kCheckPtr);
7075     dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
7076     dnsMsg->Validate(host, kInAdditionalSection);
7077 
7078     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7079     Log("Send a query for non-existing record and validate the response with NSEC");
7080 
7081     AdvanceTime(2000);
7082 
7083     sDnsMessages.Clear();
7084     SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeA, ResourceRecord::kClassInternet, /* aTruncated */ false,
7085               /* aLegacyUnicastQuery */ true);
7086 
7087     AdvanceTime(1000);
7088 
7089     dnsMsg = sDnsMessages.GetHead();
7090     VerifyOrQuit(dnsMsg != nullptr);
7091     dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 1);
7092     VerifyOrQuit(dnsMsg->mAdditionalRecords.ContainsNsec(hostFullName, ResourceRecord::kTypeAaaa));
7093 
7094     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
7095 
7096     sDnsMessages.Clear();
7097 
7098     SuccessOrQuit(mdns->UnregisterHost(host));
7099 
7100     AdvanceTime(15000);
7101 
7102     SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
7103     VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
7104 
7105     Log("End of test");
7106 
7107     testFreeInstance(sInstance);
7108 }
7109 
7110 } // namespace Multicast
7111 } // namespace Dns
7112 } // namespace ot
7113 
7114 #endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
7115 
main(void)7116 int main(void)
7117 {
7118 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
7119     ot::Dns::Multicast::TestHostReg();
7120     ot::Dns::Multicast::TestKeyReg();
7121     ot::Dns::Multicast::TestServiceReg();
7122     ot::Dns::Multicast::TestUnregisterBeforeProbeFinished();
7123     ot::Dns::Multicast::TestServiceSubTypeReg();
7124     ot::Dns::Multicast::TestHostOrServiceAndKeyReg();
7125     ot::Dns::Multicast::TestQuery();
7126     ot::Dns::Multicast::TestMultiPacket();
7127     ot::Dns::Multicast::TestQuestionUnicastDisallowed();
7128     ot::Dns::Multicast::TestTxMessageSizeLimit();
7129     ot::Dns::Multicast::TestHostConflict();
7130     ot::Dns::Multicast::TestServiceConflict();
7131 
7132     ot::Dns::Multicast::TestBrowser();
7133     ot::Dns::Multicast::TestSrvResolver();
7134     ot::Dns::Multicast::TestTxtResolver();
7135     ot::Dns::Multicast::TestIp6AddrResolver();
7136     ot::Dns::Multicast::TestPassiveCache();
7137     ot::Dns::Multicast::TestLegacyUnicastResponse();
7138 
7139     printf("All tests passed\n");
7140 #else
7141     printf("mDNS feature is not enabled\n");
7142 #endif
7143 
7144     return 0;
7145 }
7146