1 /*
2 * Copyright (c) 2020, 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 <string.h>
30
31 #include <openthread/config.h>
32
33 #include "test_platform.h"
34 #include "test_util.hpp"
35
36 #include "common/array.hpp"
37 #include "common/instance.hpp"
38 #include "net/dns_types.hpp"
39
40 namespace ot {
41
TestDnsName(void)42 void TestDnsName(void)
43 {
44 enum
45 {
46 kMaxSize = 300,
47 kMaxNameLength = Dns::Name::kMaxNameSize - 1,
48 };
49
50 struct TestName
51 {
52 const char *mName;
53 uint16_t mEncodedLength;
54 const uint8_t *mEncodedData;
55 const char **mLabels;
56 const char *mExpectedReadName;
57 };
58
59 Instance *instance;
60 MessagePool *messagePool;
61 Message *message;
62 uint8_t buffer[kMaxSize];
63 uint16_t len;
64 uint16_t offset;
65 char label[Dns::Name::kMaxLabelSize];
66 uint8_t labelLength;
67 char name[Dns::Name::kMaxNameSize];
68 const char *subDomain;
69 const char *domain;
70 const char *domain2;
71 const char *fullName;
72 const char *suffixName;
73
74 static const uint8_t kEncodedName1[] = {7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0};
75 static const uint8_t kEncodedName2[] = {3, 'f', 'o', 'o', 1, 'a', 2, 'b', 'b', 3, 'e', 'd', 'u', 0};
76 static const uint8_t kEncodedName3[] = {10, 'f', 'o', 'u', 'n', 'd', 'a', 't', 'i', 'o', 'n', 0};
77 static const uint8_t kEncodedName4[] = {0};
78
79 static const char *kLabels1[] = {"example", "com", nullptr};
80 static const char *kLabels2[] = {"foo", "a", "bb", "edu", nullptr};
81 static const char *kLabels3[] = {"foundation", nullptr};
82 static const char *kLabels4[] = {nullptr};
83
84 static const TestName kTestNames[] = {
85 {"example.com", sizeof(kEncodedName1), kEncodedName1, kLabels1, "example.com."},
86 {"example.com.", sizeof(kEncodedName1), kEncodedName1, kLabels1, "example.com."},
87 {"foo.a.bb.edu", sizeof(kEncodedName2), kEncodedName2, kLabels2, "foo.a.bb.edu."},
88 {"foo.a.bb.edu.", sizeof(kEncodedName2), kEncodedName2, kLabels2, "foo.a.bb.edu."},
89 {"foundation", sizeof(kEncodedName3), kEncodedName3, kLabels3, "foundation."},
90 {"foundation.", sizeof(kEncodedName3), kEncodedName3, kLabels3, "foundation."},
91 {"", sizeof(kEncodedName4), kEncodedName4, kLabels4, "."},
92 {".", sizeof(kEncodedName4), kEncodedName4, kLabels4, "."},
93 {nullptr, sizeof(kEncodedName4), kEncodedName4, kLabels4, "."},
94 };
95
96 static const char *kMaxLengthNames[] = {
97 "HereIsSomeoneHidden.MyHoldFromMeTaken.FromSelfHasMeDriven.MyLeadFromMeTaken."
98 "HereIsSomeoneHidden.AsLifeSweeterThanLife.TakesMeToGardenOfSoul.MyFortFromMeTaken."
99 "HereIsSomeoneHidden.LikeSugarInSugarCane.ASweetSugarTrader.MyShopFromMeTaken."
100 "SorcererAndMagicia.",
101
102 "HereIsSomeoneHidden.MyHoldFromMeTaken.FromSelfHasMeDriven.MyLeadFromMeTaken."
103 "HereIsSomeoneHidden.AsLifeSweeterThanLife.TakesMeToGardenOfSoul.MyFortFromMeTaken."
104 "HereIsSomeoneHidden.LikeSugarInSugarCane.ASweetSugarTrader.MyShopFromMeTaken."
105 "SorcererAndMagicia",
106 };
107
108 static const char *kInvalidNames[] = {
109 "foo..bar",
110 "..",
111 "a..",
112 "..b",
113
114 // Long label
115 "a.an-invalid-very-long-label-string-with-more-than-sixty-four-characters.com",
116
117 // Long name (more than 255 characters)
118 "HereIsSomeoneHidden.MyHoldFromMeTaken.FromSelfHasMeDriven.MyLeadFromMeTaken."
119 "HereIsSomeoneHidden.AsLifeSweeterThanLife.TakesMeToGardenOfSoul.MyFortFromMeTaken."
120 "HereIsSomeoneHidden.LikeSugarInSugarCane.ASweetSugarTrader.MyShopFromMeTaken."
121 "SorcererAndMagician.NoEyesCanEverSee.AnArtfulConjurer.MySenseFromMeTaken."
122 "MyEyesWillNeverSee.BeautiesOfTheWholeWorld.BeholdWhoseVisionFine.MySightFromMeTaken"
123 "PoemByRumiMolana",
124
125 // Long name of 255 characters which ends with a dot
126 "HereIsSomeoneHidden.MyHoldFromMeTaken.FromSelfHasMeDriven.MyLeadFromMeTaken."
127 "HereIsSomeoneHidden.AsLifeSweeterThanLife.TakesMeToGardenOfSoul.MyFortFromMeTaken."
128 "HereIsSomeoneHidden.LikeSugarInSugarCane.ASweetSugarTrader.MyShopFromMeTaken."
129 "SorcererAndMagician.",
130
131 // Long name of 254 characters which does not end with a dot
132 "HereIsSomeoneHidden.MyHoldFromMeTaken.FromSelfHasMeDriven.MyLeadFromMeTaken."
133 "HereIsSomeoneHidden.AsLifeSweeterThanLife.TakesMeToGardenOfSoul.MyFortFromMeTaken."
134 "HereIsSomeoneHidden.LikeSugarInSugarCane.ASweetSugarTrader.MyShopFromMeTaken."
135 "SorcererAndMagician",
136
137 };
138
139 static const char kBadLabel[] = "badlabel";
140 static const char kBadName[] = "bad.name";
141
142 printf("================================================================\n");
143 printf("TestDnsName()\n");
144
145 instance = static_cast<Instance *>(testInitInstance());
146 VerifyOrQuit(instance != nullptr, "Null OpenThread instance");
147
148 messagePool = &instance->Get<MessagePool>();
149 VerifyOrQuit((message = messagePool->Allocate(Message::kTypeIp6)) != nullptr);
150
151 message->SetOffset(0);
152
153 printf("----------------------------------------------------------------\n");
154 printf("Verify domain name match:\n");
155
156 subDomain = "my-service._ipps._tcp.local.";
157 domain = "local.";
158 VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
159
160 subDomain = "my-service._ipps._tcp.local";
161 domain = "local.";
162 VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
163
164 subDomain = "my-service._ipps._tcp.local.";
165 domain = "local";
166 VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
167
168 subDomain = "my-service._ipps._tcp.local";
169 domain = "local";
170 VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
171
172 subDomain = "my-service._ipps._tcp.default.service.arpa.";
173 domain = "default.service.arpa.";
174 VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
175
176 subDomain = "my-service._ipps._tcp.default.service.arpa.";
177 domain = "service.arpa.";
178 VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
179
180 // Verify it doesn't match a portion of a label.
181 subDomain = "my-service._ipps._tcp.default.service.arpa.";
182 domain = "vice.arpa.";
183 VerifyOrQuit(!Dns::Name::IsSubDomainOf(subDomain, domain));
184
185 // Validate case does not matter
186
187 subDomain = "my-service._ipps._tcp.local.";
188 domain = "LOCAL.";
189 VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
190
191 subDomain = "my-service._ipps._tcp.local";
192 domain = "LOCAL.";
193 VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
194
195 subDomain = "my-service._ipps._tcp.local.";
196 domain = "LOCAL";
197 VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
198
199 subDomain = "my-service._ipps._tcp.local";
200 domain = "LOCAL";
201 VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
202
203 subDomain = "my-service._ipps._tcp.Default.Service.ARPA.";
204 domain = "dEFAULT.Service.arpa.";
205 VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
206
207 subDomain = "my-service._ipps._tcp.default.service.ARpa.";
208 domain = "SeRvIcE.arPA.";
209 VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
210
211 // Verify it doesn't match a portion of a label.
212 subDomain = "my-service._ipps._tcp.default.service.arpa.";
213 domain = "Vice.arpa.";
214 VerifyOrQuit(!Dns::Name::IsSubDomainOf(subDomain, domain));
215
216 domain = "example.com.";
217 domain2 = "example.com.";
218 VerifyOrQuit(Dns::Name::IsSameDomain(domain, domain2));
219
220 domain = "example.com.";
221 domain2 = "example.com";
222 VerifyOrQuit(Dns::Name::IsSameDomain(domain, domain2));
223
224 domain = "example.com.";
225 domain2 = "ExAmPlE.cOm";
226 VerifyOrQuit(Dns::Name::IsSameDomain(domain, domain2));
227
228 domain = "example.com";
229 domain2 = "ExAmPlE.cOm";
230 VerifyOrQuit(Dns::Name::IsSameDomain(domain, domain2));
231
232 domain = "example.com.";
233 domain2 = "ExAmPlE.cOm.";
234 VerifyOrQuit(Dns::Name::IsSameDomain(domain, domain2));
235
236 domain = "example.com.";
237 domain2 = "aExAmPlE.cOm.";
238 VerifyOrQuit(!Dns::Name::IsSameDomain(domain, domain2));
239
240 domain = "example.com.";
241 domain2 = "cOm.";
242 VerifyOrQuit(!Dns::Name::IsSameDomain(domain, domain2));
243
244 domain = "example.";
245 domain2 = "example.com.";
246 VerifyOrQuit(!Dns::Name::IsSameDomain(domain, domain2));
247
248 domain = "example.com.";
249 domain2 = ".example.com.";
250 VerifyOrQuit(!Dns::Name::IsSameDomain(domain, domain2));
251
252 printf("----------------------------------------------------------------\n");
253 printf("Extracting label(s) and removing domains:\n");
254
255 fullName = "my-service._ipps._tcp.default.service.arpa.";
256 suffixName = "default.service.arpa.";
257 SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)));
258 VerifyOrQuit(strcmp(name, "my-service._ipps._tcp") == 0);
259
260 fullName = "my.service._ipps._tcp.default.service.arpa.";
261 suffixName = "_ipps._tcp.default.service.arpa.";
262 SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)));
263 VerifyOrQuit(strcmp(name, "my.service") == 0);
264
265 fullName = "my-service._ipps._tcp.default.service.arpa.";
266 suffixName = "DeFault.SerVice.ARPA.";
267 SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)));
268 VerifyOrQuit(strcmp(name, "my-service._ipps._tcp") == 0);
269
270 fullName = "my-service._ipps._tcp.default.service.arpa.";
271 suffixName = "efault.service.arpa.";
272 VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)) == kErrorParse);
273
274 fullName = "my-service._ipps._tcp.default.service.arpa.";
275 suffixName = "xdefault.service.arpa.";
276 VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)) == kErrorParse);
277
278 fullName = "my-service._ipps._tcp.default.service.arpa.";
279 suffixName = ".default.service.arpa.";
280 VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)) == kErrorParse);
281
282 fullName = "my-service._ipps._tcp.default.service.arpa.";
283 suffixName = "default.service.arp.";
284 VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)) == kErrorParse);
285
286 fullName = "default.service.arpa.";
287 suffixName = "default.service.arpa.";
288 VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)) == kErrorParse);
289
290 fullName = "efault.service.arpa.";
291 suffixName = "default.service.arpa.";
292 VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, sizeof(name)) == kErrorParse);
293
294 fullName = "my-service._ipps._tcp.default.service.arpa.";
295 suffixName = "default.service.arpa.";
296 SuccessOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, 22));
297 VerifyOrQuit(strcmp(name, "my-service._ipps._tcp") == 0);
298
299 fullName = "my-service._ipps._tcp.default.service.arpa.";
300 suffixName = "default.service.arpa.";
301 VerifyOrQuit(Dns::Name::ExtractLabels(fullName, suffixName, name, 21) == kErrorNoBufs);
302
303 printf("----------------------------------------------------------------\n");
304 printf("Append names, check encoded bytes, parse name and read labels:\n");
305
306 for (const TestName &test : kTestNames)
307 {
308 IgnoreError(message->SetLength(0));
309
310 SuccessOrQuit(Dns::Name::AppendName(test.mName, *message));
311
312 len = message->GetLength();
313 SuccessOrQuit(message->Read(0, buffer, len));
314
315 DumpBuffer(test.mName, buffer, len);
316
317 VerifyOrQuit(len == test.mEncodedLength, "Encoded length does not match expected value");
318 VerifyOrQuit(memcmp(buffer, test.mEncodedData, len) == 0, "Encoded name data does not match expected data");
319
320 // Parse and skip over the name
321 offset = 0;
322 SuccessOrQuit(Dns::Name::ParseName(*message, offset));
323 VerifyOrQuit(offset == len, "Name::ParseName() returned incorrect offset");
324
325 // Read labels one by one.
326 offset = 0;
327
328 for (uint8_t index = 0; test.mLabels[index] != nullptr; index++)
329 {
330 labelLength = sizeof(label);
331 SuccessOrQuit(Dns::Name::ReadLabel(*message, offset, label, labelLength));
332
333 printf("Label[%d] = \"%s\"\n", index, label);
334
335 VerifyOrQuit(strcmp(label, test.mLabels[index]) == 0, "Name::ReadLabel() did not get expected label");
336 VerifyOrQuit(labelLength == strlen(label), "Name::ReadLabel() returned incorrect label length");
337 }
338
339 labelLength = sizeof(label);
340 VerifyOrQuit(Dns::Name::ReadLabel(*message, offset, label, labelLength) == kErrorNotFound,
341 "Name::ReadLabel() failed at end of the name");
342
343 // Read entire name
344 offset = 0;
345 SuccessOrQuit(Dns::Name::ReadName(*message, offset, name, sizeof(name)));
346
347 printf("Read name =\"%s\"\n", name);
348
349 VerifyOrQuit(strcmp(name, test.mExpectedReadName) == 0, "Name::ReadName() did not get expected name");
350 VerifyOrQuit(offset == len, "Name::ReadName() returned incorrect offset");
351
352 // Read entire name with different name buffer sizes (just right and one byte off the expected size)
353 offset = 0;
354 SuccessOrQuit(
355 Dns::Name::ReadName(*message, offset, name, static_cast<uint16_t>(strlen(test.mExpectedReadName) + 1)),
356 "Name::ReadName() failed with exact name buffer size");
357 offset = 0;
358 VerifyOrQuit(Dns::Name::ReadName(*message, offset, name,
359 static_cast<uint16_t>(strlen(test.mExpectedReadName))) == kErrorNoBufs,
360 "Name::ReadName() did not fail with too small name buffer size");
361
362 // Compare labels one by one.
363 offset = 0;
364
365 for (uint8_t index = 0; test.mLabels[index] != nullptr; index++)
366 {
367 uint16_t startOffset = offset;
368
369 strcpy(label, test.mLabels[index]);
370
371 SuccessOrQuit(Dns::Name::CompareLabel(*message, offset, label));
372 VerifyOrQuit(offset != startOffset, "Name::CompareLabel() did not change offset");
373
374 offset = startOffset;
375 VerifyOrQuit(Dns::Name::CompareLabel(*message, offset, kBadLabel) == kErrorNotFound,
376 "Name::CompareLabel() did not fail with incorrect label");
377
378 StringConvertToUppercase(label);
379
380 offset = startOffset;
381 SuccessOrQuit(Dns::Name::CompareLabel(*message, offset, label));
382 }
383
384 // Compare the whole name.
385 strcpy(name, test.mExpectedReadName);
386
387 offset = 0;
388 SuccessOrQuit(Dns::Name::CompareName(*message, offset, name));
389 VerifyOrQuit(offset == len, "Name::CompareName() returned incorrect offset");
390
391 StringConvertToUppercase(name);
392
393 offset = 0;
394 SuccessOrQuit(Dns::Name::CompareName(*message, offset, name));
395
396 offset = 0;
397 VerifyOrQuit(Dns::Name::CompareName(*message, offset, kBadName) == kErrorNotFound,
398 "Name::CompareName() did not fail with incorrect name");
399 VerifyOrQuit(offset == len, "Name::CompareName() returned incorrect offset");
400
401 // Remove the terminating '.' in expected name and verify
402 // that it can still be used by `CompareName()`.
403 offset = 0;
404 strcpy(name, test.mExpectedReadName);
405 name[strlen(name) - 1] = '\0';
406 SuccessOrQuit(Dns::Name::CompareName(*message, offset, name));
407 VerifyOrQuit(offset == len, "Name::CompareName() returned incorrect offset");
408
409 if (strlen(name) >= 1)
410 {
411 name[strlen(name) - 1] = '\0';
412 offset = 0;
413 VerifyOrQuit(Dns::Name::CompareName(*message, offset, name) == kErrorNotFound,
414 "Name::CompareName() did not fail with invalid name");
415 VerifyOrQuit(offset == len, "Name::CompareName() returned incorrect offset");
416 }
417
418 // Compare the name with itself read from message.
419 offset = 0;
420 SuccessOrQuit(Dns::Name::CompareName(*message, offset, *message, offset));
421 VerifyOrQuit(offset == len, "Name::CompareName() returned incorrect offset");
422 }
423
424 printf("----------------------------------------------------------------\n");
425 printf("Max length names:\n");
426
427 for (const char *&maxLengthName : kMaxLengthNames)
428 {
429 if (maxLengthName[strlen(maxLengthName) - 1] == '.')
430 {
431 VerifyOrQuit(strlen(maxLengthName) == kMaxNameLength);
432 }
433 else
434 {
435 VerifyOrQuit(strlen(maxLengthName) == kMaxNameLength - 1);
436 }
437
438 IgnoreError(message->SetLength(0));
439
440 printf("\"%s\"\n", maxLengthName);
441
442 SuccessOrQuit(Dns::Name::AppendName(maxLengthName, *message));
443 }
444
445 printf("----------------------------------------------------------------\n");
446 printf("Invalid names:\n");
447
448 for (const char *&invalidName : kInvalidNames)
449 {
450 IgnoreError(message->SetLength(0));
451
452 printf("\"%s\"\n", invalidName);
453
454 VerifyOrQuit(Dns::Name::AppendName(invalidName, *message) == kErrorInvalidArgs);
455 }
456
457 printf("----------------------------------------------------------------\n");
458 printf("Append as multiple labels and terminator instead of full name:\n");
459
460 for (const TestName &test : kTestNames)
461 {
462 IgnoreError(message->SetLength(0));
463
464 SuccessOrQuit(Dns::Name::AppendMultipleLabels(test.mName, *message));
465 SuccessOrQuit(Dns::Name::AppendTerminator(*message));
466
467 len = message->GetLength();
468 SuccessOrQuit(message->Read(0, buffer, len));
469
470 DumpBuffer(test.mName, buffer, len);
471
472 VerifyOrQuit(len == test.mEncodedLength, "Encoded length does not match expected value");
473 VerifyOrQuit(memcmp(buffer, test.mEncodedData, len) == 0, "Encoded name data does not match expected data");
474 }
475
476 printf("----------------------------------------------------------------\n");
477 printf("Append labels one by one:\n");
478
479 for (const TestName &test : kTestNames)
480 {
481 IgnoreError(message->SetLength(0));
482
483 for (uint8_t index = 0; test.mLabels[index] != nullptr; index++)
484 {
485 SuccessOrQuit(Dns::Name::AppendLabel(test.mLabels[index], *message));
486 }
487
488 SuccessOrQuit(Dns::Name::AppendTerminator(*message));
489
490 len = message->GetLength();
491 SuccessOrQuit(message->Read(0, buffer, len));
492
493 DumpBuffer(test.mName, buffer, len);
494
495 VerifyOrQuit(len == test.mEncodedLength, "Encoded length does not match expected value");
496 VerifyOrQuit(memcmp(buffer, test.mEncodedData, len) == 0, "Encoded name data does not match expected data");
497 }
498
499 message->Free();
500 testFreeInstance(instance);
501 }
502
TestDnsCompressedName(void)503 void TestDnsCompressedName(void)
504 {
505 enum
506 {
507 kHeaderOffset = 10,
508 kGuardBlockSize = 20,
509 kMaxBufferSize = 100,
510 kLabelSize = 64,
511 kNameSize = 256,
512
513 kName2EncodedSize = 4 + 2, // encoded "FOO" + pointer label (2 bytes)
514 kName3EncodedSize = 2, // pointer label (2 bytes)
515 kName4EncodedSize = 15 + 2, // encoded "Human.Readable" + pointer label (2 bytes).
516
517 };
518
519 const char kName[] = "F.ISI.ARPA";
520 const char kLabel1[] = "FOO";
521 const char kInstanceLabel[] = "Human.Readable";
522
523 static const uint8_t kEncodedName[] = {1, 'F', 3, 'I', 'S', 'I', 4, 'A', 'R', 'P', 'A', 0};
524 static const uint8_t kIsiRelativeIndex = 2; // Index in kEncodedName to the start of "ISI.ARPA" portion.
525
526 static const char *kName1Labels[] = {"F", "ISI", "ARPA"};
527 static const char *kName2Labels[] = {"FOO", "F", "ISI", "ARPA"};
528 static const char *kName3Labels[] = {"ISI", "ARPA"};
529 static const char *kName4Labels[] = {"Human.Readable", "F", "ISI", "ARPA"};
530
531 static const char kExpectedReadName1[] = "F.ISI.ARPA.";
532 static const char kExpectedReadName2[] = "FOO.F.ISI.ARPA.";
533 static const char kExpectedReadName3[] = "ISI.ARPA.";
534 static const char kExpectedReadName4[] = "Human.Readable.F.ISI.ARPA.";
535
536 static const char kBadName[] = "bad.name";
537
538 Instance *instance;
539 MessagePool *messagePool;
540 Message *message;
541 Message *message2;
542 uint16_t offset;
543 uint16_t name1Offset;
544 uint16_t name2Offset;
545 uint16_t name3Offset;
546 uint16_t name4Offset;
547 uint8_t buffer[kMaxBufferSize];
548 char label[kLabelSize];
549 uint8_t labelLength;
550 char name[kNameSize];
551 Dns::Name dnsName1;
552 Dns::Name dnsName2;
553 Dns::Name dnsName3;
554 Dns::Name dnsName4;
555
556 printf("================================================================\n");
557 printf("TestDnsCompressedName()\n");
558
559 instance = static_cast<Instance *>(testInitInstance());
560 VerifyOrQuit(instance != nullptr, "Null OpenThread instance");
561
562 messagePool = &instance->Get<MessagePool>();
563 VerifyOrQuit((message = messagePool->Allocate(Message::kTypeIp6)) != nullptr);
564
565 // Append name1 "F.ISI.ARPA"
566
567 for (uint8_t index = 0; index < kHeaderOffset + kGuardBlockSize; index++)
568 {
569 SuccessOrQuit(message->Append(index));
570 }
571
572 message->SetOffset(kHeaderOffset);
573
574 name1Offset = message->GetLength();
575 SuccessOrQuit(Dns::Name::AppendName(kName, *message));
576
577 // Append name2 "FOO.F.ISI.ARPA" as a compressed name after some guard/extra bytes
578
579 for (uint8_t index = 0; index < kGuardBlockSize; index++)
580 {
581 uint8_t value = 0xff;
582 SuccessOrQuit(message->Append(value));
583 }
584
585 name2Offset = message->GetLength();
586
587 SuccessOrQuit(Dns::Name::AppendLabel(kLabel1, *message));
588 SuccessOrQuit(Dns::Name::AppendPointerLabel(name1Offset - kHeaderOffset, *message));
589
590 // Append name3 "ISI.ARPA" as a compressed name after some guard/extra bytes
591
592 for (uint8_t index = 0; index < kGuardBlockSize; index++)
593 {
594 uint8_t value = 0xaa;
595 SuccessOrQuit(message->Append(value));
596 }
597
598 name3Offset = message->GetLength();
599 SuccessOrQuit(Dns::Name::AppendPointerLabel(name1Offset + kIsiRelativeIndex - kHeaderOffset, *message));
600
601 name4Offset = message->GetLength();
602 SuccessOrQuit(Dns::Name::AppendLabel(kInstanceLabel, *message));
603 SuccessOrQuit(Dns::Name::AppendPointerLabel(name1Offset - kHeaderOffset, *message));
604
605 printf("----------------------------------------------------------------\n");
606 printf("Read and parse the uncompressed name-1 \"F.ISI.ARPA\"\n");
607
608 SuccessOrQuit(message->Read(name1Offset, buffer, sizeof(kEncodedName)));
609
610 DumpBuffer(kName, buffer, sizeof(kEncodedName));
611 VerifyOrQuit(memcmp(buffer, kEncodedName, sizeof(kEncodedName)) == 0,
612 "Encoded name data does not match expected data");
613
614 offset = name1Offset;
615 SuccessOrQuit(Dns::Name::ParseName(*message, offset));
616
617 VerifyOrQuit(offset == name1Offset + sizeof(kEncodedName), "Name::ParseName() returned incorrect offset");
618
619 offset = name1Offset;
620
621 for (const char *nameLabel : kName1Labels)
622 {
623 labelLength = sizeof(label);
624 SuccessOrQuit(Dns::Name::ReadLabel(*message, offset, label, labelLength));
625
626 printf("label: \"%s\"\n", label);
627 VerifyOrQuit(strcmp(label, nameLabel) == 0, "Name::ReadLabel() did not get expected label");
628 VerifyOrQuit(labelLength == strlen(label), "Name::ReadLabel() returned incorrect label length");
629 }
630
631 labelLength = sizeof(label);
632 VerifyOrQuit(Dns::Name::ReadLabel(*message, offset, label, labelLength) == kErrorNotFound,
633 "Name::ReadLabel() failed at end of the name");
634
635 offset = name1Offset;
636 SuccessOrQuit(Dns::Name::ReadName(*message, offset, name, sizeof(name)));
637 printf("Read name =\"%s\"\n", name);
638 VerifyOrQuit(strcmp(name, kExpectedReadName1) == 0, "Name::ReadName() did not return expected name");
639 VerifyOrQuit(offset == name1Offset + sizeof(kEncodedName), "Name::ReadName() returned incorrect offset");
640
641 offset = name1Offset;
642
643 for (const char *nameLabel : kName1Labels)
644 {
645 SuccessOrQuit(Dns::Name::CompareLabel(*message, offset, nameLabel));
646 }
647
648 offset = name1Offset;
649 SuccessOrQuit(Dns::Name::CompareName(*message, offset, kExpectedReadName1));
650 VerifyOrQuit(offset == name1Offset + sizeof(kEncodedName), "Name::CompareName() returned incorrect offset");
651
652 offset = name1Offset;
653 VerifyOrQuit(Dns::Name::CompareName(*message, offset, kBadName) == kErrorNotFound,
654 "Name::CompareName() did not fail with incorrect name");
655 VerifyOrQuit(offset == name1Offset + sizeof(kEncodedName), "Name::CompareName() returned incorrect offset");
656
657 offset = name1Offset;
658 SuccessOrQuit(Dns::Name::CompareName(*message, offset, *message, offset));
659 VerifyOrQuit(offset == name1Offset + sizeof(kEncodedName), "Name::CompareName() returned incorrect offset");
660
661 offset = name1Offset;
662 VerifyOrQuit(Dns::Name::CompareName(*message, offset, *message, name2Offset) == kErrorNotFound,
663 "Name::CompareName() did not fail with mismatching name");
664 VerifyOrQuit(offset == name1Offset + sizeof(kEncodedName), "Name::CompareName() returned incorrect offset");
665
666 printf("----------------------------------------------------------------\n");
667 printf("Read and parse compressed name-2 \"FOO.F.ISI.ARPA\"\n");
668
669 SuccessOrQuit(message->Read(name2Offset, buffer, kName2EncodedSize));
670 DumpBuffer("name2(compressed)", buffer, kName2EncodedSize);
671
672 offset = name2Offset;
673 SuccessOrQuit(Dns::Name::ParseName(*message, offset));
674 VerifyOrQuit(offset == name2Offset + kName2EncodedSize, "Name::ParseName() returned incorrect offset");
675
676 offset = name2Offset;
677
678 for (const char *nameLabel : kName2Labels)
679 {
680 labelLength = sizeof(label);
681 SuccessOrQuit(Dns::Name::ReadLabel(*message, offset, label, labelLength));
682
683 printf("label: \"%s\"\n", label);
684 VerifyOrQuit(strcmp(label, nameLabel) == 0, "Name::ReadLabel() did not get expected label");
685 VerifyOrQuit(labelLength == strlen(label), "Name::ReadLabel() returned incorrect label length");
686 }
687
688 labelLength = sizeof(label);
689 VerifyOrQuit(Dns::Name::ReadLabel(*message, offset, label, labelLength) == kErrorNotFound,
690 "Name::ReadLabel() failed at end of the name");
691
692 offset = name2Offset;
693 SuccessOrQuit(Dns::Name::ReadName(*message, offset, name, sizeof(name)));
694 printf("Read name =\"%s\"\n", name);
695 VerifyOrQuit(strcmp(name, kExpectedReadName2) == 0, "Name::ReadName() did not return expected name");
696 VerifyOrQuit(offset == name2Offset + kName2EncodedSize, "Name::ReadName() returned incorrect offset");
697
698 offset = name2Offset;
699
700 for (const char *nameLabel : kName2Labels)
701 {
702 SuccessOrQuit(Dns::Name::CompareLabel(*message, offset, nameLabel));
703 }
704
705 offset = name2Offset;
706 SuccessOrQuit(Dns::Name::CompareName(*message, offset, kExpectedReadName2));
707 VerifyOrQuit(offset == name2Offset + kName2EncodedSize, "Name::CompareName() returned incorrect offset");
708
709 offset = name2Offset;
710 VerifyOrQuit(Dns::Name::CompareName(*message, offset, kBadName) == kErrorNotFound,
711 "Name::CompareName() did not fail with incorrect name");
712 VerifyOrQuit(offset == name2Offset + kName2EncodedSize, "Name::CompareName() returned incorrect offset");
713
714 offset = name2Offset;
715 SuccessOrQuit(Dns::Name::CompareName(*message, offset, *message, offset), "Name::CompareName() with itself failed");
716 VerifyOrQuit(offset == name2Offset + kName2EncodedSize, "Name::CompareName() returned incorrect offset");
717
718 offset = name2Offset;
719 VerifyOrQuit(Dns::Name::CompareName(*message, offset, *message, name3Offset) == kErrorNotFound,
720 "Name::CompareName() did not fail with mismatching name");
721 VerifyOrQuit(offset == name2Offset + kName2EncodedSize, "Name::CompareName() returned incorrect offset");
722
723 printf("----------------------------------------------------------------\n");
724 printf("Read and parse compressed name-3 \"ISI.ARPA\"\n");
725
726 SuccessOrQuit(message->Read(name3Offset, buffer, kName3EncodedSize));
727 DumpBuffer("name2(compressed)", buffer, kName3EncodedSize);
728
729 offset = name3Offset;
730 SuccessOrQuit(Dns::Name::ParseName(*message, offset));
731 VerifyOrQuit(offset == name3Offset + kName3EncodedSize, "Name::ParseName() returned incorrect offset");
732
733 offset = name3Offset;
734
735 for (const char *nameLabel : kName3Labels)
736 {
737 labelLength = sizeof(label);
738 SuccessOrQuit(Dns::Name::ReadLabel(*message, offset, label, labelLength));
739
740 printf("label: \"%s\"\n", label);
741 VerifyOrQuit(strcmp(label, nameLabel) == 0, "Name::ReadLabel() did not get expected label");
742 VerifyOrQuit(labelLength == strlen(label), "Name::ReadLabel() returned incorrect label length");
743 }
744
745 labelLength = sizeof(label);
746 VerifyOrQuit(Dns::Name::ReadLabel(*message, offset, label, labelLength) == kErrorNotFound,
747 "Name::ReadLabel() failed at end of the name");
748
749 offset = name3Offset;
750 SuccessOrQuit(Dns::Name::ReadName(*message, offset, name, sizeof(name)));
751 printf("Read name =\"%s\"\n", name);
752 VerifyOrQuit(strcmp(name, kExpectedReadName3) == 0, "Name::ReadName() did not return expected name");
753 VerifyOrQuit(offset == name3Offset + kName3EncodedSize, "Name::ReadName() returned incorrect offset");
754
755 offset = name3Offset;
756
757 for (const char *nameLabel : kName3Labels)
758 {
759 SuccessOrQuit(Dns::Name::CompareLabel(*message, offset, nameLabel));
760 }
761
762 offset = name3Offset;
763 SuccessOrQuit(Dns::Name::CompareName(*message, offset, kExpectedReadName3));
764 VerifyOrQuit(offset == name3Offset + kName3EncodedSize, "Name::CompareName() returned incorrect offset");
765
766 offset = name3Offset;
767 VerifyOrQuit(Dns::Name::CompareName(*message, offset, kBadName) == kErrorNotFound,
768 "Name::CompareName() did not fail with incorrect name");
769 VerifyOrQuit(offset == name3Offset + kName3EncodedSize, "Name::CompareName() returned incorrect offset");
770
771 offset = name3Offset;
772 SuccessOrQuit(Dns::Name::CompareName(*message, offset, *message, offset), "Name::CompareName() with itself failed");
773 VerifyOrQuit(offset == name3Offset + kName3EncodedSize, "Name::CompareName() returned incorrect offset");
774
775 offset = name3Offset;
776 VerifyOrQuit(Dns::Name::CompareName(*message, offset, *message, name4Offset) == kErrorNotFound,
777 "Name::CompareName() did not fail with mismatching name");
778 VerifyOrQuit(offset == name3Offset + kName3EncodedSize, "Name::CompareName() returned incorrect offset");
779
780 printf("----------------------------------------------------------------\n");
781 printf("Read and parse the uncompressed name-4 \"Human\\.Readable.F.ISI.ARPA\"\n");
782
783 SuccessOrQuit(message->Read(name4Offset, buffer, kName4EncodedSize));
784 DumpBuffer("name4(compressed)", buffer, kName4EncodedSize);
785
786 offset = name4Offset;
787 SuccessOrQuit(Dns::Name::ParseName(*message, offset));
788 VerifyOrQuit(offset == name4Offset + kName4EncodedSize, "Name::ParseName() returned incorrect offset");
789
790 offset = name4Offset;
791
792 for (const char *nameLabel : kName4Labels)
793 {
794 labelLength = sizeof(label);
795 SuccessOrQuit(Dns::Name::ReadLabel(*message, offset, label, labelLength));
796
797 printf("label: \"%s\"\n", label);
798 VerifyOrQuit(strcmp(label, nameLabel) == 0, "Name::ReadLabel() did not get expected label");
799 VerifyOrQuit(labelLength == strlen(label), "Name::ReadLabel() returned incorrect label length");
800 }
801
802 // `ReadName()` for name-4 should still succeed since only the first label contains dot char
803 offset = name4Offset;
804 SuccessOrQuit(Dns::Name::ReadName(*message, offset, name, sizeof(name)));
805 printf("Read name =\"%s\"\n", name);
806 VerifyOrQuit(strcmp(name, kExpectedReadName4) == 0, "Name::ReadName() did not return expected name");
807 VerifyOrQuit(offset == name4Offset + kName4EncodedSize, "Name::ParseName() returned incorrect offset");
808
809 offset = name4Offset;
810
811 for (const char *nameLabel : kName4Labels)
812 {
813 SuccessOrQuit(Dns::Name::CompareLabel(*message, offset, nameLabel));
814 }
815
816 offset = name4Offset;
817 SuccessOrQuit(Dns::Name::CompareName(*message, offset, *message, offset), "Name::CompareName() with itself failed");
818
819 offset = name4Offset;
820 VerifyOrQuit(Dns::Name::CompareName(*message, offset, *message, name1Offset) == kErrorNotFound,
821 "Name::CompareName() did not fail with mismatching name");
822
823 printf("----------------------------------------------------------------\n");
824 printf("Append names from one message to another\n");
825
826 VerifyOrQuit((message2 = messagePool->Allocate(Message::kTypeIp6)) != nullptr);
827
828 dnsName1.SetFromMessage(*message, name1Offset);
829 dnsName2.SetFromMessage(*message, name2Offset);
830 dnsName3.SetFromMessage(*message, name3Offset);
831 dnsName4.SetFromMessage(*message, name4Offset);
832
833 offset = 0;
834 SuccessOrQuit(dnsName1.AppendTo(*message2));
835 SuccessOrQuit(dnsName2.AppendTo(*message2));
836 SuccessOrQuit(dnsName3.AppendTo(*message2));
837 SuccessOrQuit(dnsName4.AppendTo(*message2));
838
839 SuccessOrQuit(message2->Read(0, buffer, message2->GetLength()));
840 DumpBuffer("message2", buffer, message2->GetLength());
841
842 // Now compare the names one by one in `message2`. Note that
843 // `CompareName()` will update `offset` on success.
844
845 SuccessOrQuit(Dns::Name::CompareName(*message2, offset, dnsName1));
846 SuccessOrQuit(Dns::Name::CompareName(*message2, offset, dnsName2));
847 SuccessOrQuit(Dns::Name::CompareName(*message2, offset, dnsName3));
848 SuccessOrQuit(Dns::Name::CompareName(*message2, offset, dnsName4));
849
850 offset = 0;
851 SuccessOrQuit(Dns::Name::ReadName(*message2, offset, name, sizeof(name)));
852 printf("- Name1 after `AppendTo()`: \"%s\"\n", name);
853 SuccessOrQuit(Dns::Name::ReadName(*message2, offset, name, sizeof(name)));
854 printf("- Name2 after `AppendTo()`: \"%s\"\n", name);
855 SuccessOrQuit(Dns::Name::ReadName(*message2, offset, name, sizeof(name)));
856 printf("- Name3 after `AppendTo()`: \"%s\"\n", name);
857 // `ReadName()` for name-4 will fail due to first label containing dot char.
858
859 message->Free();
860 message2->Free();
861 testFreeInstance(instance);
862 }
863
TestHeaderAndResourceRecords(void)864 void TestHeaderAndResourceRecords(void)
865 {
866 enum
867 {
868 kHeaderOffset = 0,
869 kQuestionCount = 1,
870 kAnswerCount = 2,
871 kAdditionalCount = 5,
872 kTtl = 7200,
873 kTxtTtl = 7300,
874 kSrvPort = 1234,
875 kSrvPriority = 1,
876 kSrvWeight = 2,
877 kMaxSize = 600,
878 };
879
880 const char kMessageString[] = "DnsMessage";
881 const char kDomainName[] = "example.com.";
882 const char kServiceLabels[] = "_service._udp";
883 const char kServiceName[] = "_service._udp.example.com.";
884 const char kInstance1Label[] = "inst1";
885 const char kInstance2Label[] = "instance.2"; // Instance label includes dot '.' character.
886 const char kInstance1Name[] = "inst1._service._udp.example.com.";
887 const char kInstance2Name[] = "instance.2._service._udp.example.com.";
888 const char kHostName[] = "host.example.com.";
889 const uint8_t kTxtData[] = {9, 'k', 'e', 'y', '=', 'v', 'a', 'l', 'u', 'e', 0};
890 const char kHostAddress[] = "fd00::abcd:";
891
892 const char *kInstanceLabels[] = {kInstance1Label, kInstance2Label};
893 const char *kInstanceNames[] = {kInstance1Name, kInstance2Name};
894
895 Instance *instance;
896 MessagePool *messagePool;
897 Message *message;
898 Dns::Header header;
899 uint16_t messageId;
900 uint16_t headerOffset;
901 uint16_t offset;
902 uint16_t numRecords;
903 uint16_t len;
904 uint16_t serviceNameOffset;
905 uint16_t hostNameOffset;
906 uint16_t answerSectionOffset;
907 uint16_t additionalSectionOffset;
908 uint16_t index;
909 Dns::PtrRecord ptrRecord;
910 Dns::SrvRecord srvRecord;
911 Dns::TxtRecord txtRecord;
912 Dns::AaaaRecord aaaaRecord;
913 Dns::ResourceRecord record;
914 Ip6::Address hostAddress;
915
916 char label[Dns::Name::kMaxLabelSize];
917 char name[Dns::Name::kMaxNameSize];
918 uint8_t buffer[kMaxSize];
919
920 printf("================================================================\n");
921 printf("TestHeaderAndResourceRecords()\n");
922
923 instance = static_cast<Instance *>(testInitInstance());
924 VerifyOrQuit(instance != nullptr, "Null OpenThread instance");
925
926 messagePool = &instance->Get<MessagePool>();
927 VerifyOrQuit((message = messagePool->Allocate(Message::kTypeIp6)) != nullptr);
928
929 printf("----------------------------------------------------------------\n");
930 printf("Preparing the message\n");
931
932 SuccessOrQuit(message->Append(kMessageString));
933
934 // Header
935
936 headerOffset = message->GetLength();
937 SuccessOrQuit(header.SetRandomMessageId());
938 messageId = header.GetMessageId();
939 header.SetType(Dns::Header::kTypeResponse);
940 header.SetQuestionCount(kQuestionCount);
941 header.SetAnswerCount(kAnswerCount);
942 header.SetAdditionalRecordCount(kAdditionalCount);
943 SuccessOrQuit(message->Append(header));
944 message->SetOffset(headerOffset);
945
946 // Question section
947
948 serviceNameOffset = message->GetLength() - headerOffset;
949 SuccessOrQuit(Dns::Name::AppendMultipleLabels(kServiceLabels, *message));
950 SuccessOrQuit(Dns::Name::AppendName(kDomainName, *message));
951 SuccessOrQuit(message->Append(Dns::Question(Dns::ResourceRecord::kTypePtr)));
952
953 // Answer section
954
955 answerSectionOffset = message->GetLength();
956
957 for (const char *instanceLabel : kInstanceLabels)
958 {
959 SuccessOrQuit(Dns::Name::AppendPointerLabel(serviceNameOffset, *message));
960 ptrRecord.Init();
961 ptrRecord.SetTtl(kTtl);
962 offset = message->GetLength();
963 SuccessOrQuit(message->Append(ptrRecord));
964 SuccessOrQuit(Dns::Name::AppendLabel(instanceLabel, *message));
965 SuccessOrQuit(Dns::Name::AppendPointerLabel(serviceNameOffset, *message));
966 ptrRecord.SetLength(message->GetLength() - offset - sizeof(Dns::ResourceRecord));
967 message->Write(offset, ptrRecord);
968 }
969
970 // Additional section
971
972 additionalSectionOffset = message->GetLength();
973
974 for (const char *instanceName : kInstanceNames)
975 {
976 uint16_t instanceNameOffset = message->GetLength() - headerOffset;
977
978 // SRV record
979 SuccessOrQuit(Dns::Name::AppendName(instanceName, *message));
980 srvRecord.Init();
981 srvRecord.SetTtl(kTtl);
982 srvRecord.SetPort(kSrvPort);
983 srvRecord.SetWeight(kSrvWeight);
984 srvRecord.SetPriority(kSrvPriority);
985 offset = message->GetLength();
986 SuccessOrQuit(message->Append(srvRecord));
987 hostNameOffset = message->GetLength() - headerOffset;
988 SuccessOrQuit(Dns::Name::AppendName(kHostName, *message));
989 srvRecord.SetLength(message->GetLength() - offset - sizeof(Dns::ResourceRecord));
990 message->Write(offset, srvRecord);
991
992 // TXT record
993 SuccessOrQuit(Dns::Name::AppendPointerLabel(instanceNameOffset, *message));
994 txtRecord.Init();
995 txtRecord.SetTtl(kTxtTtl);
996 txtRecord.SetLength(sizeof(kTxtData));
997 SuccessOrQuit(message->Append(txtRecord));
998 SuccessOrQuit(message->Append(kTxtData));
999 }
1000
1001 SuccessOrQuit(hostAddress.FromString(kHostAddress));
1002 SuccessOrQuit(Dns::Name::AppendPointerLabel(hostNameOffset, *message));
1003 aaaaRecord.Init();
1004 aaaaRecord.SetTtl(kTtl);
1005 aaaaRecord.SetAddress(hostAddress);
1006 SuccessOrQuit(message->Append(aaaaRecord));
1007
1008 // Dump the entire message
1009
1010 VerifyOrQuit(message->GetLength() < kMaxSize, "Message is too long");
1011 SuccessOrQuit(message->Read(0, buffer, message->GetLength()));
1012 DumpBuffer("message", buffer, message->GetLength());
1013
1014 printf("----------------------------------------------------------------\n");
1015 printf("Parse and verify the message\n");
1016
1017 offset = 0;
1018 VerifyOrQuit(message->Compare(offset, kMessageString), "Message header does not match");
1019 offset += sizeof(kMessageString);
1020
1021 // Header
1022
1023 VerifyOrQuit(offset == headerOffset, "headerOffset is incorrect");
1024 SuccessOrQuit(message->Read(offset, header));
1025 offset += sizeof(header);
1026
1027 VerifyOrQuit(header.GetMessageId() == messageId);
1028 VerifyOrQuit(header.GetType() == Dns::Header::kTypeResponse);
1029 VerifyOrQuit(header.GetQuestionCount() == kQuestionCount);
1030 VerifyOrQuit(header.GetAnswerCount() == kAnswerCount);
1031 VerifyOrQuit(header.GetAdditionalRecordCount() == kAdditionalCount);
1032
1033 printf("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
1034 printf("Question Section\n");
1035
1036 SuccessOrQuit(Dns::Name::CompareName(*message, offset, kServiceName), "Question name does not match");
1037 VerifyOrQuit(message->Compare(offset, Dns::Question(Dns::ResourceRecord::kTypePtr)));
1038 offset += sizeof(Dns::Question);
1039
1040 printf("PTR for \"%s\"\n", kServiceName);
1041
1042 printf("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
1043 printf("Answer Section\n");
1044
1045 VerifyOrQuit(offset == answerSectionOffset, "answer section offset is incorrect");
1046
1047 for (const char *instanceLabel : kInstanceLabels)
1048 {
1049 SuccessOrQuit(Dns::Name::CompareName(*message, offset, kServiceName));
1050 SuccessOrQuit(Dns::ResourceRecord::ReadRecord(*message, offset, ptrRecord));
1051 VerifyOrQuit(ptrRecord.GetTtl() == kTtl, "Read PTR is incorrect");
1052
1053 SuccessOrQuit(ptrRecord.ReadPtrName(*message, offset, label, sizeof(label), name, sizeof(name)));
1054 VerifyOrQuit(strcmp(label, instanceLabel) == 0, "Inst label is incorrect");
1055 VerifyOrQuit(strcmp(name, kServiceName) == 0);
1056
1057 printf(" \"%s\" PTR %u %d \"%s.%s\"\n", kServiceName, ptrRecord.GetTtl(), ptrRecord.GetLength(), label,
1058 name);
1059 }
1060
1061 VerifyOrQuit(offset == additionalSectionOffset, "offset is incorrect after answer section parse");
1062
1063 offset = answerSectionOffset;
1064 SuccessOrQuit(Dns::ResourceRecord::ParseRecords(*message, offset, kAnswerCount));
1065 VerifyOrQuit(offset == additionalSectionOffset, "offset is incorrect after answer section parse");
1066
1067 printf("Use FindRecord() to find and iterate through all the records:\n");
1068
1069 offset = answerSectionOffset;
1070 numRecords = kAnswerCount;
1071
1072 while (numRecords > 0)
1073 {
1074 uint16_t prevNumRecords = numRecords;
1075
1076 SuccessOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, numRecords, Dns::Name(kServiceName)));
1077 VerifyOrQuit(numRecords == prevNumRecords - 1, "Incorrect num records");
1078 SuccessOrQuit(Dns::ResourceRecord::ReadRecord(*message, offset, ptrRecord));
1079 VerifyOrQuit(ptrRecord.GetTtl() == kTtl, "Read PTR is incorrect");
1080 SuccessOrQuit(ptrRecord.ReadPtrName(*message, offset, label, sizeof(label), name, sizeof(name)));
1081 printf(" \"%s\" PTR %u %d inst:\"%s\" at \"%s\"\n", kServiceName, ptrRecord.GetTtl(), ptrRecord.GetLength(),
1082 label, name);
1083 }
1084
1085 VerifyOrQuit(offset == additionalSectionOffset, "offset is incorrect after answer section parse");
1086 VerifyOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, numRecords, Dns::Name(kServiceName)) ==
1087 kErrorNotFound,
1088 "FindRecord did not fail with no records");
1089
1090 // Use `ReadRecord()` with a non-matching record type. Verify that it correct skips over the record.
1091
1092 offset = answerSectionOffset;
1093 numRecords = kAnswerCount;
1094
1095 while (numRecords > 0)
1096 {
1097 SuccessOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, numRecords, Dns::Name(kServiceName)));
1098 VerifyOrQuit(Dns::ResourceRecord::ReadRecord(*message, offset, srvRecord) == kErrorNotFound,
1099 "ReadRecord() did not fail with non-matching type");
1100 }
1101
1102 VerifyOrQuit(offset == additionalSectionOffset, "offset is incorrect after answer section parse");
1103
1104 // Use `FindRecord` with a non-matching name. Verify that it correctly skips over all records.
1105
1106 offset = answerSectionOffset;
1107 numRecords = kAnswerCount;
1108 VerifyOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, numRecords, Dns::Name(kInstance1Name)) ==
1109 kErrorNotFound,
1110 "FindRecord did not fail with non-matching name");
1111 VerifyOrQuit(numRecords == 0, "Incorrect num records");
1112 VerifyOrQuit(offset == additionalSectionOffset, "offset is incorrect after answer section parse");
1113
1114 printf("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
1115 printf("Additional Section\n");
1116
1117 for (const char *instanceName : kInstanceNames)
1118 {
1119 uint16_t savedOffset;
1120
1121 // SRV record
1122 SuccessOrQuit(Dns::Name::CompareName(*message, offset, instanceName));
1123 SuccessOrQuit(Dns::ResourceRecord::ReadRecord(*message, offset, srvRecord));
1124 VerifyOrQuit(srvRecord.GetTtl() == kTtl);
1125 VerifyOrQuit(srvRecord.GetPort() == kSrvPort);
1126 VerifyOrQuit(srvRecord.GetWeight() == kSrvWeight);
1127 VerifyOrQuit(srvRecord.GetPriority() == kSrvPriority);
1128 SuccessOrQuit(srvRecord.ReadTargetHostName(*message, offset, name, sizeof(name)));
1129 VerifyOrQuit(strcmp(name, kHostName) == 0);
1130 printf(" \"%s\" SRV %u %d %d %d %d \"%s\"\n", instanceName, srvRecord.GetTtl(), srvRecord.GetLength(),
1131 srvRecord.GetPort(), srvRecord.GetWeight(), srvRecord.GetPriority(), name);
1132
1133 // TXT record
1134 SuccessOrQuit(Dns::Name::CompareName(*message, offset, instanceName));
1135 SuccessOrQuit(Dns::ResourceRecord::ReadRecord(*message, offset, txtRecord));
1136 VerifyOrQuit(txtRecord.GetTtl() == kTxtTtl);
1137 savedOffset = offset;
1138 len = sizeof(buffer);
1139 SuccessOrQuit(txtRecord.ReadTxtData(*message, offset, buffer, len));
1140 VerifyOrQuit(len == sizeof(kTxtData));
1141 VerifyOrQuit(memcmp(buffer, kTxtData, len) == 0);
1142 printf(" \"%s\" TXT %u %d \"%s\"\n", instanceName, txtRecord.GetTtl(), txtRecord.GetLength(),
1143 reinterpret_cast<const char *>(buffer));
1144
1145 // Partial read of TXT data
1146 len = sizeof(kTxtData) - 1;
1147 memset(buffer, 0, sizeof(buffer));
1148 VerifyOrQuit(txtRecord.ReadTxtData(*message, savedOffset, buffer, len) == kErrorNoBufs);
1149 VerifyOrQuit(len == sizeof(kTxtData) - 1);
1150 VerifyOrQuit(memcmp(buffer, kTxtData, len) == 0);
1151 VerifyOrQuit(savedOffset == offset);
1152 }
1153
1154 SuccessOrQuit(Dns::Name::CompareName(*message, offset, kHostName));
1155 SuccessOrQuit(Dns::ResourceRecord::ReadRecord(*message, offset, aaaaRecord));
1156 VerifyOrQuit(aaaaRecord.GetTtl() == kTtl);
1157 VerifyOrQuit(aaaaRecord.GetAddress() == hostAddress);
1158 printf(" \"%s\" AAAA %u %d \"%s\"\n", kHostName, aaaaRecord.GetTtl(), aaaaRecord.GetLength(),
1159 aaaaRecord.GetAddress().ToString().AsCString());
1160
1161 VerifyOrQuit(offset == message->GetLength(), "offset is incorrect after additional section parse");
1162
1163 // Use `ParseRecords()` to parse all records
1164 offset = additionalSectionOffset;
1165 SuccessOrQuit(Dns::ResourceRecord::ParseRecords(*message, offset, kAdditionalCount));
1166 VerifyOrQuit(offset == message->GetLength(), "offset is incorrect after additional section parse");
1167
1168 printf("Use FindRecord() to search for specific name:\n");
1169
1170 for (const char *instanceName : kInstanceNames)
1171 {
1172 offset = additionalSectionOffset;
1173 numRecords = kAdditionalCount;
1174
1175 SuccessOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, numRecords, Dns::Name(instanceName)));
1176 SuccessOrQuit(Dns::ResourceRecord::ReadRecord(*message, offset, srvRecord));
1177 SuccessOrQuit(Dns::Name::ParseName(*message, offset));
1178 printf(" \"%s\" SRV %u %d %d %d %d\n", instanceName, srvRecord.GetTtl(), srvRecord.GetLength(),
1179 srvRecord.GetPort(), srvRecord.GetWeight(), srvRecord.GetPriority());
1180
1181 SuccessOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, numRecords, Dns::Name(instanceName)));
1182 SuccessOrQuit(Dns::ResourceRecord::ReadRecord(*message, offset, txtRecord));
1183 offset += txtRecord.GetLength();
1184 printf(" \"%s\" TXT %u %d\n", instanceName, txtRecord.GetTtl(), txtRecord.GetLength());
1185
1186 VerifyOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, numRecords, Dns::Name(instanceName)) ==
1187 kErrorNotFound,
1188 "FindRecord() did not fail with no more records");
1189
1190 VerifyOrQuit(offset == message->GetLength(), "offset is incorrect after additional section parse");
1191 }
1192
1193 offset = additionalSectionOffset;
1194 numRecords = kAdditionalCount;
1195 SuccessOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, numRecords, Dns::Name(kHostName)));
1196
1197 SuccessOrQuit(Dns::ResourceRecord::ReadRecord(*message, offset, record));
1198 VerifyOrQuit(record.GetType() == Dns::ResourceRecord::kTypeAaaa);
1199 offset += record.GetLength();
1200 VerifyOrQuit(offset == message->GetLength(), "offset is incorrect after additional section parse");
1201
1202 printf("Use FindRecord() to search for specific records:\n");
1203 printf(" Answer Section\n");
1204
1205 for (index = 0; index < GetArrayLength(kInstanceNames); index++)
1206 {
1207 offset = answerSectionOffset;
1208 SuccessOrQuit(
1209 Dns::ResourceRecord::FindRecord(*message, offset, kAnswerCount, index, Dns::Name(kServiceName), ptrRecord));
1210
1211 printf(" index:%d -> \"%s\" PTR %u %d\n", index, kServiceName, ptrRecord.GetTtl(), ptrRecord.GetLength());
1212 }
1213
1214 // Check `FindRecord()` failure with non-matching name, record type, or bad index.
1215
1216 offset = answerSectionOffset;
1217 VerifyOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, kAnswerCount, index, Dns::Name(kServiceName),
1218 ptrRecord) == kErrorNotFound,
1219 "FindRecord() did not fail with bad index");
1220 VerifyOrQuit(offset == answerSectionOffset, "FindRecord() changed offset on failure");
1221
1222 offset = answerSectionOffset;
1223 VerifyOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, kAnswerCount, index, Dns::Name(kInstance1Name),
1224 ptrRecord) == kErrorNotFound,
1225 "FindRecord() did not fail with bad index");
1226 VerifyOrQuit(offset == answerSectionOffset, "FindRecord() changed offset on failure");
1227
1228 offset = answerSectionOffset;
1229 VerifyOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, kAnswerCount, index, Dns::Name(kServiceName),
1230 txtRecord) == kErrorNotFound,
1231 "FindRecord() did not fail with bad index");
1232 VerifyOrQuit(offset == answerSectionOffset, "FindRecord() changed offset on failure");
1233
1234 printf(" Additional Section\n");
1235
1236 for (const char *instanceName : kInstanceNames)
1237 {
1238 // There is a single SRV and TXT entry for each instance
1239 offset = additionalSectionOffset;
1240 SuccessOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, kAdditionalCount, /* aIndex */ 0,
1241 Dns::Name(instanceName), srvRecord));
1242 printf(" \"%s\" SRV %u %d %d %d %d \n", instanceName, srvRecord.GetTtl(), srvRecord.GetLength(),
1243 srvRecord.GetPort(), srvRecord.GetWeight(), srvRecord.GetPriority());
1244
1245 offset = additionalSectionOffset;
1246 SuccessOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, kAdditionalCount, /* aIndex */ 0,
1247 Dns::Name(instanceName), txtRecord));
1248 printf(" \"%s\" TXT %u %d\n", instanceName, txtRecord.GetTtl(), txtRecord.GetLength());
1249
1250 offset = additionalSectionOffset;
1251 VerifyOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, kAdditionalCount, /* aIndex */ 1,
1252 Dns::Name(instanceName), srvRecord) == kErrorNotFound);
1253
1254 offset = additionalSectionOffset;
1255 VerifyOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, kAdditionalCount, /* aIndex */ 1,
1256 Dns::Name(instanceName), txtRecord) == kErrorNotFound);
1257 }
1258
1259 for (index = 0; index < kAdditionalCount; index++)
1260 {
1261 offset = additionalSectionOffset;
1262 // Find record with empty name (matching any) and any type.
1263 SuccessOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, kAdditionalCount, index, Dns::Name(), record));
1264 }
1265
1266 offset = additionalSectionOffset;
1267 VerifyOrQuit(Dns::ResourceRecord::FindRecord(*message, offset, kAdditionalCount, index, Dns::Name(), record) ==
1268 kErrorNotFound);
1269
1270 message->Free();
1271 testFreeInstance(instance);
1272 }
1273
TestDnsTxtEntry(void)1274 void TestDnsTxtEntry(void)
1275 {
1276 enum
1277 {
1278 kMaxTxtDataSize = 255,
1279 };
1280
1281 struct EncodedTxtData
1282 {
1283 const uint8_t *mData;
1284 uint8_t mLength;
1285 };
1286
1287 const char kKey1[] = "key";
1288 const uint8_t kValue1[] = {'v', 'a', 'l', 'u', 'e'};
1289
1290 const char kKey2[] = "E";
1291 const uint8_t kValue2[] = {'m', 'c', '^', '2'};
1292
1293 const char kKey3[] = "space key";
1294 const uint8_t kValue3[] = {'=', 0, '='};
1295
1296 const char kKey4[] = "123456789"; // Max recommended length key
1297 const uint8_t kValue4[] = {0};
1298
1299 const char kKey5[] = "1234567890"; // Longer than recommended key
1300 const uint8_t kValue5[] = {'a'};
1301
1302 const char kKey6[] = "boolKey"; // Should be encoded as "boolKey" (without `=`).
1303 const char kKey7[] = "emptyKey"; // Should be encoded as "emptyKey=".
1304
1305 // Invalid key
1306 const char kShortKey[] = "";
1307
1308 const uint8_t kEncodedTxt1[] = {9, 'k', 'e', 'y', '=', 'v', 'a', 'l', 'u', 'e'};
1309 const uint8_t kEncodedTxt2[] = {6, 'E', '=', 'm', 'c', '^', '2'};
1310 const uint8_t kEncodedTxt3[] = {13, 's', 'p', 'a', 'c', 'e', ' ', 'k', 'e', 'y', '=', '=', 0, '='};
1311 const uint8_t kEncodedTxt4[] = {11, '1', '2', '3', '4', '5', '6', '7', '8', '9', '=', 0};
1312 const uint8_t kEncodedTxt5[] = {12, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '=', 'a'};
1313 const uint8_t kEncodedTxt6[] = {7, 'b', 'o', 'o', 'l', 'K', 'e', 'y'};
1314 const uint8_t kEncodedTxt7[] = {9, 'e', 'm', 'p', 't', 'y', 'K', 'e', 'y', '='};
1315
1316 const uint8_t kInvalidEncodedTxt1[] = {4, 'a', '=', 'b'}; // Incorrect length
1317
1318 // Special encoded txt data with zero strings and string starting
1319 // with '=' (missing key) which should be skipped over silently.
1320 const uint8_t kSpecialEncodedTxt[] = {0, 0, 3, 'A', '=', 'B', 2, '=', 'C', 3, 'D', '=', 'E', 3, '=', '1', '2'};
1321
1322 const Dns::TxtEntry kTxtEntries[] = {
1323 Dns::TxtEntry(kKey1, kValue1, sizeof(kValue1)),
1324 Dns::TxtEntry(kKey2, kValue2, sizeof(kValue2)),
1325 Dns::TxtEntry(kKey3, kValue3, sizeof(kValue3)),
1326 Dns::TxtEntry(kKey4, kValue4, sizeof(kValue4)),
1327 Dns::TxtEntry(kKey5, kValue5, sizeof(kValue5)),
1328 Dns::TxtEntry(kKey6, nullptr, 0),
1329 Dns::TxtEntry(kKey7, kValue1, 0),
1330 };
1331
1332 const EncodedTxtData kEncodedTxtData[] = {
1333 {kEncodedTxt1, sizeof(kEncodedTxt1)}, {kEncodedTxt2, sizeof(kEncodedTxt2)},
1334 {kEncodedTxt3, sizeof(kEncodedTxt3)}, {kEncodedTxt4, sizeof(kEncodedTxt4)},
1335 {kEncodedTxt5, sizeof(kEncodedTxt5)}, {kEncodedTxt6, sizeof(kEncodedTxt6)},
1336 {kEncodedTxt7, sizeof(kEncodedTxt7)}};
1337
1338 Instance *instance;
1339 MessagePool *messagePool;
1340 Message *message;
1341 uint8_t txtData[kMaxTxtDataSize];
1342 uint16_t txtDataLength;
1343 uint8_t index;
1344 Dns::TxtEntry txtEntry;
1345 Dns::TxtEntry::Iterator iterator;
1346 MutableData<kWithUint16Length> data;
1347
1348 printf("================================================================\n");
1349 printf("TestDnsTxtEntry()\n");
1350
1351 instance = static_cast<Instance *>(testInitInstance());
1352 VerifyOrQuit(instance != nullptr);
1353
1354 messagePool = &instance->Get<MessagePool>();
1355 VerifyOrQuit((message = messagePool->Allocate(Message::kTypeIp6)) != nullptr);
1356
1357 data.Init(txtData, sizeof(txtData));
1358 SuccessOrQuit(Dns::TxtEntry::AppendEntries(kTxtEntries, GetArrayLength(kTxtEntries), data));
1359 VerifyOrQuit(data.GetBytes() == txtData);
1360 txtDataLength = data.GetLength();
1361 VerifyOrQuit(txtDataLength < kMaxTxtDataSize, "TXT data is too long");
1362 DumpBuffer("txt data", txtData, txtDataLength);
1363
1364 SuccessOrQuit(Dns::TxtEntry::AppendEntries(kTxtEntries, GetArrayLength(kTxtEntries), *message));
1365 VerifyOrQuit(txtDataLength == message->GetLength());
1366 VerifyOrQuit(message->CompareBytes(0, txtData, txtDataLength));
1367
1368 index = 0;
1369 for (const EncodedTxtData &encodedData : kEncodedTxtData)
1370 {
1371 VerifyOrQuit(memcmp(&txtData[index], encodedData.mData, encodedData.mLength) == 0);
1372 index += encodedData.mLength;
1373 }
1374
1375 iterator.Init(txtData, txtDataLength);
1376
1377 for (const Dns::TxtEntry &expectedTxtEntry : kTxtEntries)
1378 {
1379 uint8_t expectedKeyLength = static_cast<uint8_t>(strlen(expectedTxtEntry.mKey));
1380
1381 SuccessOrQuit(iterator.GetNextEntry(txtEntry), "TxtEntry::GetNextEntry() failed");
1382 printf("key:\"%s\" valueLen:%d\n", txtEntry.mKey != nullptr ? txtEntry.mKey : "(null)", txtEntry.mValueLength);
1383
1384 if (expectedKeyLength > Dns::TxtEntry::kMaxKeyLength)
1385 {
1386 // When the key is longer than recommended max key length,
1387 // the full encoded string is returned in `mValue` and
1388 // `mValueLength` and `mKey` should be set to `nullptr`.
1389
1390 VerifyOrQuit(txtEntry.mKey == nullptr, "TxtEntry key does not match expected value for long key");
1391 VerifyOrQuit(txtEntry.mValueLength == expectedKeyLength + expectedTxtEntry.mValueLength + sizeof(char),
1392 "TxtEntry value length is incorrect for long key");
1393 VerifyOrQuit(memcmp(txtEntry.mValue, expectedTxtEntry.mKey, expectedKeyLength) == 0);
1394 VerifyOrQuit(txtEntry.mValue[expectedKeyLength] == static_cast<uint8_t>('='));
1395 VerifyOrQuit(memcmp(&txtEntry.mValue[expectedKeyLength + sizeof(uint8_t)], expectedTxtEntry.mValue,
1396 expectedTxtEntry.mValueLength) == 0);
1397 continue;
1398 }
1399
1400 VerifyOrQuit(strcmp(txtEntry.mKey, expectedTxtEntry.mKey) == 0);
1401 VerifyOrQuit(txtEntry.mValueLength == expectedTxtEntry.mValueLength);
1402
1403 if (txtEntry.mValueLength != 0)
1404 {
1405 VerifyOrQuit(memcmp(txtEntry.mValue, expectedTxtEntry.mValue, txtEntry.mValueLength) == 0);
1406 }
1407 else
1408 {
1409 // Ensure both `txtEntry.mKey` and `expectedTxtEntry.mKey` are
1410 // null or both are non-null (for boolean or empty keys).
1411 VerifyOrQuit((txtEntry.mKey == nullptr) == (expectedTxtEntry.mKey == nullptr),
1412 "TxtEntry value does not match expected value for bool or empty key");
1413 }
1414 }
1415
1416 VerifyOrQuit(iterator.GetNextEntry(txtEntry) == kErrorNotFound, "GetNextEntry() returned unexpected entry");
1417 VerifyOrQuit(iterator.GetNextEntry(txtEntry) == kErrorNotFound, "GetNextEntry() succeeded after done");
1418
1419 // Verify `AppendEntries()` correctly rejecting invalid key
1420 txtEntry.mValue = kValue1;
1421 txtEntry.mValueLength = sizeof(kValue1);
1422 txtEntry.mKey = kShortKey;
1423 VerifyOrQuit(Dns::TxtEntry::AppendEntries(&txtEntry, 1, *message) == kErrorInvalidArgs,
1424 "AppendEntries() did not fail with invalid key");
1425
1426 // Verify appending empty txt data
1427
1428 SuccessOrQuit(message->SetLength(0));
1429
1430 data.Init(txtData, sizeof(txtData));
1431 SuccessOrQuit(Dns::TxtEntry::AppendEntries(nullptr, 0, data), "AppendEntries() failed with empty array");
1432 txtDataLength = data.GetLength();
1433 VerifyOrQuit(txtDataLength == sizeof(uint8_t), "Data length is incorrect with empty array");
1434 VerifyOrQuit(txtData[0] == 0, "Data is invalid with empty array");
1435
1436 SuccessOrQuit(Dns::TxtEntry::AppendEntries(nullptr, 0, *message), "AppendEntries() failed with empty array");
1437 VerifyOrQuit(message->GetLength() == txtDataLength);
1438 VerifyOrQuit(message->CompareBytes(0, txtData, txtDataLength));
1439
1440 SuccessOrQuit(message->SetLength(0));
1441 txtEntry.mKey = nullptr;
1442 txtEntry.mValue = nullptr;
1443 txtEntry.mValueLength = 0;
1444 SuccessOrQuit(Dns::TxtEntry::AppendEntries(&txtEntry, 1, *message), "AppendEntries() failed with empty entry");
1445 txtDataLength = message->GetLength();
1446 VerifyOrQuit(txtDataLength == sizeof(uint8_t), "Data length is incorrect with empty entry");
1447 SuccessOrQuit(message->Read(0, txtData, txtDataLength), "Failed to read txt data from message");
1448 VerifyOrQuit(txtData[0] == 0, "Data is invalid with empty entry");
1449
1450 // Verify `Iterator` behavior with invalid txt data.
1451
1452 iterator.Init(kInvalidEncodedTxt1, sizeof(kInvalidEncodedTxt1));
1453 VerifyOrQuit(iterator.GetNextEntry(txtEntry) == kErrorParse, "GetNextEntry() did not fail with invalid data");
1454
1455 // Verify `GetNextEntry()` correctly skipping over empty strings and
1456 // strings starting with '=' (missing key) in encoded txt.
1457 //
1458 // kSpecialEncodedTxt:
1459 // { 0, 3, 'A', '=', 'B', 2, '=', 'C', 3, 'D', '=', 'E', 3, '=', '1', '2' }
1460
1461 iterator.Init(kSpecialEncodedTxt, sizeof(kSpecialEncodedTxt));
1462
1463 // We should get "A=B` (or key="A", and value="B")
1464 SuccessOrQuit(iterator.GetNextEntry(txtEntry), "GetNextEntry() failed");
1465 VerifyOrQuit((txtEntry.mKey[0] == 'A') && (txtEntry.mKey[1] == '\0'), "GetNextEntry() got incorrect key");
1466 VerifyOrQuit((txtEntry.mValueLength == 1) && (txtEntry.mValue[0] == 'B'), "GetNextEntry() got incorrect value");
1467
1468 // We should get "D=E` (or key="D", and value="E")
1469 SuccessOrQuit(iterator.GetNextEntry(txtEntry), "GetNextEntry() failed");
1470 VerifyOrQuit((txtEntry.mKey[0] == 'D') && (txtEntry.mKey[1] == '\0'), "GetNextEntry() got incorrect key");
1471 VerifyOrQuit((txtEntry.mValueLength == 1) && (txtEntry.mValue[0] == 'E'), "GetNextEntry() got incorrect value");
1472
1473 VerifyOrQuit(iterator.GetNextEntry(txtEntry) == kErrorNotFound, "GetNextEntry() returned extra entry");
1474
1475 message->Free();
1476 testFreeInstance(instance);
1477 }
1478
1479 } // namespace ot
1480
main(void)1481 int main(void)
1482 {
1483 ot::TestDnsName();
1484 ot::TestDnsCompressedName();
1485 ot::TestHeaderAndResourceRecords();
1486 ot::TestDnsTxtEntry();
1487
1488 printf("All tests passed\n");
1489 return 0;
1490 }
1491