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 ®Callbck : 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 ®Callbck : 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 ®Callbck : 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 ®Callbck : 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