1 /*
2 * Copyright (c) 2017 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/sys/crc.h>
10 #include <dns_pack.h>
11 #include <dns_internal.h>
12
13 #define MAX_BUF_SIZE 512
14 /* RFC 1035, 4.1.1. Header section format */
15 #define DNS_HEADER_SIZE 12
16
17 static uint8_t dns_buf[MAX_BUF_SIZE];
18 static uint16_t dns_buf_len;
19
20 static uint8_t qname[MAX_BUF_SIZE];
21 static uint16_t qname_len;
22
23 static struct dns_resolve_context dns_ctx;
24
25 /* Domain: www.zephyrproject.org
26 * Type: standard query (IPv4)
27 * Transaction ID: 0xda0f
28 * Recursion desired
29 */
30 static uint8_t query_ipv4[] = { 0xda, 0x0f, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
31 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
32 0x0d, 0x7a, 0x65, 0x70, 0x68, 0x79, 0x72, 0x70,
33 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x03, 0x6f,
34 0x72, 0x67, 0x00, 0x00, 0x01, 0x00, 0x01 };
35
36 #define DNAME1 "www.zephyrproject.org"
37
38 /* Domain: zephyr.local
39 * Type: standard query (IPv6)
40 * Recursion not desired
41 */
42 static uint8_t query_mdns[] = {
43 0xda, 0x0f, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
44 0x00, 0x00, 0x00, 0x00, 0x06, 0x7a, 0x65, 0x70,
45 0x68, 0x79, 0x72, 0x05, 0x6c, 0x6f, 0x63, 0x61,
46 0x6c, 0x00, 0x00, 0x01, 0x00, 0x01,
47 };
48
49 #define ZEPHYR_LOCAL "zephyr.local"
50
51 static uint16_t tid1 = 0xda0f;
52
eval_query(const char * dname,uint16_t tid,enum dns_rr_type type,uint8_t * expected,uint16_t expected_len)53 static int eval_query(const char *dname, uint16_t tid, enum dns_rr_type type,
54 uint8_t *expected, uint16_t expected_len)
55 {
56 uint8_t *question;
57 int rc;
58
59 rc = dns_msg_pack_qname(&qname_len, qname, MAX_BUF_SIZE, dname);
60 if (rc != 0) {
61 goto lb_exit;
62 }
63
64 rc = dns_msg_pack_query(dns_buf, &dns_buf_len, MAX_BUF_SIZE, qname, qname_len,
65 tid, type);
66 if (rc != 0) {
67 goto lb_exit;
68 }
69
70 if (dns_unpack_header_id(dns_buf) != tid) {
71 rc = -EINVAL;
72 goto lb_exit;
73 }
74
75 /* This is a query */
76 if (dns_header_qr(dns_buf) != DNS_QUERY) {
77 rc = -EINVAL;
78 goto lb_exit;
79 }
80
81 /* This is a query (standard query) */
82 if (dns_header_opcode(dns_buf) != DNS_QUERY) {
83 rc = -EINVAL;
84 goto lb_exit;
85 }
86
87 /* Authoritative Answer must be 0 for a Query */
88 if (dns_header_aa(dns_buf) != 0) {
89 rc = -EINVAL;
90 goto lb_exit;
91 }
92
93 /* TrunCation is always 0 */
94 if (dns_header_tc(dns_buf) != 0) {
95 rc = -EINVAL;
96 goto lb_exit;
97 }
98
99 /* Recursion Desired is always 1 */
100 if (dns_header_rd(dns_buf) != 1) {
101 rc = -EINVAL;
102 goto lb_exit;
103 }
104
105 /* Recursion Available is always 0 */
106 if (dns_header_ra(dns_buf) != 0) {
107 rc = -EINVAL;
108 goto lb_exit;
109 }
110
111 /* Z is always 0 */
112 if (dns_header_z(dns_buf) != 0) {
113 rc = -EINVAL;
114 goto lb_exit;
115 }
116
117 /* Response code must be 0 (no error) */
118 if (dns_header_rcode(dns_buf) != DNS_HEADER_NOERROR) {
119 rc = -EINVAL;
120 goto lb_exit;
121 }
122
123 /* Question counter must be 1 */
124 if (dns_header_qdcount(dns_buf) != 1) {
125 rc = -EINVAL;
126 goto lb_exit;
127 }
128
129 /* Answer counter must be 0 */
130 if (dns_header_ancount(dns_buf) != 0) {
131 rc = -EINVAL;
132 goto lb_exit;
133 }
134
135 /* Name server resource records counter must be 0 */
136 if (dns_header_nscount(dns_buf) != 0) {
137 rc = -EINVAL;
138 goto lb_exit;
139 }
140
141 /* Additional records counter must be 0 */
142 if (dns_header_arcount(dns_buf) != 0) {
143 rc = -EINVAL;
144 goto lb_exit;
145 }
146
147 question = dns_buf + DNS_HEADER_SIZE;
148
149 /* QClass */
150 if (dns_unpack_query_qclass(question + qname_len) != DNS_CLASS_IN) {
151 rc = -EINVAL;
152 goto lb_exit;
153 }
154
155 /* QType */
156 if (dns_unpack_query_qtype(question + qname_len) != type) {
157 rc = -EINVAL;
158 goto lb_exit;
159 }
160
161 /* compare with the expected result */
162 if (dns_buf_len != expected_len) {
163 rc = -EINVAL;
164 goto lb_exit;
165 }
166
167 if (memcmp(expected, dns_buf, dns_buf_len) != 0) {
168 rc = -EINVAL;
169 goto lb_exit;
170 }
171
172 lb_exit:
173 return rc;
174 }
175
176 /* The DNS response min size is computed as follows:
177 * (hdr size) + (question min size) + (RR min size)
178 */
179 #define RESPONSE_MIN_SIZE (DNS_HEADER_SIZE + 6 + 14)
180
181 /* DNS QNAME size here is 2 because we use DNS pointers */
182 #define NAME_PTR_SIZE 2
183 /* DNS integer size */
184 #define INT_SIZE 2
185 /* DNS answer TTL size */
186 #define ANS_TTL_SIZE 4
187
188 struct dns_response_test {
189 /* domain name: example.com */
190 const char *dname;
191
192 /* expected result */
193 uint8_t *res;
194 /* expected result length */
195 uint16_t res_len;
196
197 /* transaction id */
198 uint16_t tid;
199 /* A, AAAA */
200 uint8_t answer_type;
201 /* answer counter */
202 uint8_t ancount;
203 /* answer TTL */
204 uint32_t ttl;
205 /* recursion available */
206 uint8_t ra;
207 /* recursion desired */
208 uint8_t rd;
209 /* data len */
210 uint8_t rdlen;
211 /* data */
212 const uint8_t *rdata;
213 };
214
215 /* This routine evaluates DNS responses with one RR, and assumes that the
216 * RR's name points to the DNS question's qname.
217 */
eval_response1(struct dns_response_test * resp,bool unpack_answer)218 static int eval_response1(struct dns_response_test *resp, bool unpack_answer)
219 {
220 uint8_t *ptr = resp->res;
221 uint16_t offset;
222 int rc;
223
224 if (resp->res_len < RESPONSE_MIN_SIZE) {
225 rc = __LINE__;
226 goto lb_exit;
227 }
228
229 if (dns_unpack_header_id(resp->res) != resp->tid) {
230 rc = __LINE__;
231 goto lb_exit;
232 }
233
234 /* This is a response */
235 if (dns_header_qr(resp->res) != DNS_RESPONSE) {
236 rc = __LINE__;
237 goto lb_exit;
238 }
239
240 /* For the DNS response, this value is standard query */
241 if (dns_header_opcode(resp->res) != DNS_QUERY) {
242 rc = __LINE__;
243 goto lb_exit;
244 }
245
246 /* Authoritative Answer */
247 if (dns_header_aa(resp->res) != 0) {
248 rc = __LINE__;
249 goto lb_exit;
250 }
251
252 /* TrunCation is always 0 */
253 if (dns_header_tc(resp->res) != 0) {
254 rc = __LINE__;
255 goto lb_exit;
256 }
257
258 /* Recursion Desired */
259 if (dns_header_rd(resp->res) != resp->rd) {
260 rc = __LINE__;
261 goto lb_exit;
262 }
263
264 /* Recursion Available */
265 if (dns_header_ra(resp->res) != resp->ra) {
266 rc = __LINE__;
267 goto lb_exit;
268 }
269
270 /* Z is always 0 */
271 if (dns_header_z(resp->res) != 0) {
272 rc = __LINE__;
273 goto lb_exit;
274 }
275
276 /* Response code must be 0 (no error) */
277 if (dns_header_rcode(resp->res) != DNS_HEADER_NOERROR) {
278 rc = __LINE__;
279 goto lb_exit;
280 }
281
282 /* Question counter must be 1 */
283 if (dns_header_qdcount(resp->res) != 1) {
284 rc = __LINE__;
285 goto lb_exit;
286 }
287
288 /* Answer counter */
289 if (dns_header_ancount(resp->res) != resp->ancount) {
290 rc = __LINE__;
291 goto lb_exit;
292 }
293
294 /* Name server resource records counter must be 0 */
295 if (dns_header_nscount(resp->res) != 0) {
296 rc = __LINE__;
297 goto lb_exit;
298 }
299
300 /* Additional records counter must be 0 */
301 if (dns_header_arcount(resp->res) != 0) {
302 rc = __LINE__;
303 goto lb_exit;
304 }
305
306 rc = dns_msg_pack_qname(&qname_len, qname, MAX_BUF_SIZE, resp->dname);
307 if (rc != 0) {
308 goto lb_exit;
309 }
310
311 offset = DNS_HEADER_SIZE;
312
313 /* DNS header + qname + qtype (int size) + qclass (int size) */
314 if (offset + qname_len + 2 * INT_SIZE >= resp->res_len) {
315 rc = __LINE__;
316 goto lb_exit;
317 }
318
319 if (memcmp(qname, resp->res + offset, qname_len) != 0) {
320 rc = __LINE__;
321 goto lb_exit;
322 }
323
324 offset += qname_len;
325
326 if (dns_unpack_query_qtype(resp->res + offset) != resp->answer_type) {
327 rc = __LINE__;
328 goto lb_exit;
329 }
330
331 if (dns_unpack_query_qclass(resp->res + offset) != DNS_CLASS_IN) {
332 rc = __LINE__;
333 goto lb_exit;
334 }
335
336 /* qtype and qclass */
337 offset += INT_SIZE + INT_SIZE;
338
339 if (unpack_answer) {
340 uint32_t ttl;
341 struct dns_msg_t msg;
342 enum dns_rr_type answer_type;
343
344 msg.msg = resp->res;
345 msg.msg_size = resp->res_len;
346 msg.answer_offset = offset;
347
348 if (dns_unpack_answer(&msg, DNS_ANSWER_MIN_SIZE, &ttl, &answer_type) < 0) {
349 rc = __LINE__;
350 goto lb_exit;
351 }
352
353 offset = msg.response_position;
354 } else {
355 /* 0xc0 and 0x0c are derived from RFC 1035 4.1.4 Message
356 * compression. 0x0c is the DNS Header Size (fixed size) and
357 * 0xc0 is the DNS pointer marker.
358 */
359 if (resp->res[offset + 0] != 0xc0 ||
360 resp->res[offset + 1] != 0x0c) {
361 rc = __LINE__;
362 goto lb_exit;
363 }
364
365 /* simplify the following lines by applying the offset here */
366 resp->res += offset;
367 offset = NAME_PTR_SIZE;
368
369 if (dns_answer_type(NAME_PTR_SIZE,
370 resp->res) != resp->answer_type) {
371 rc = __LINE__;
372 goto lb_exit;
373 }
374
375 offset += INT_SIZE;
376
377 if (dns_answer_class(NAME_PTR_SIZE,
378 resp->res) != DNS_CLASS_IN) {
379 rc = __LINE__;
380 goto lb_exit;
381 }
382
383 offset += INT_SIZE;
384
385 if (dns_answer_ttl(NAME_PTR_SIZE, resp->res) != resp->ttl) {
386 rc = __LINE__;
387 goto lb_exit;
388 }
389
390 offset += ANS_TTL_SIZE;
391
392 if (dns_answer_rdlength(NAME_PTR_SIZE,
393 resp->res) != resp->rdlen) {
394 rc = __LINE__;
395 goto lb_exit;
396 }
397
398 offset += INT_SIZE;
399 }
400
401 if (resp->rdlen + offset > resp->res_len) {
402 rc = __LINE__;
403 goto lb_exit;
404 }
405
406 if (memcmp(resp->res + offset, resp->rdata, resp->rdlen) != 0) {
407 rc = __LINE__;
408 }
409
410 lb_exit:
411 resp->res = ptr;
412
413 return -rc;
414 }
415
416
ZTEST(dns_packet,test_dns_query)417 ZTEST(dns_packet, test_dns_query)
418 {
419 int rc;
420
421 rc = eval_query(DNAME1, tid1, DNS_RR_TYPE_A,
422 query_ipv4, sizeof(query_ipv4));
423 zassert_equal(rc, 0, "Query test failed for domain: "DNAME1);
424
425 rc = eval_query(NULL, tid1, DNS_RR_TYPE_A,
426 query_ipv4, sizeof(query_ipv4));
427 zassert_not_equal(rc, 0, "Query test with invalid domain name failed");
428
429 rc = eval_query(DNAME1, tid1, DNS_RR_TYPE_AAAA,
430 query_ipv4, sizeof(query_ipv4));
431 zassert_not_equal(rc, 0, "Query test for IPv4 with RR type AAAA failed");
432
433 rc = eval_query(DNAME1, tid1 + 1, DNS_RR_TYPE_A,
434 query_ipv4, sizeof(query_ipv4));
435 zassert_not_equal(rc, 0, "Query test with invalid ID failed");
436 }
437
438 /* DNS response for www.zephyrproject.org with the following parameters:
439 * Transaction ID: 0xb041
440 * Answer type: RR A
441 * Answer counter: 1
442 * TTL: 3028
443 * Recursion Available: 1
444 * RD len: 4 (IPv4 Address)
445 * RData: 140.211.169.8
446 */
447 static uint8_t resp_ipv4[] = { 0xb0, 0x41, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
448 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
449 0x0d, 0x7a, 0x65, 0x70, 0x68, 0x79, 0x72, 0x70,
450 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x03, 0x6f,
451 0x72, 0x67, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0,
452 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0b,
453 0xd4, 0x00, 0x04, 0x8c, 0xd3, 0xa9, 0x08 };
454
455 static const uint8_t resp_ipv4_addr[] = {140, 211, 169, 8};
456
ZTEST(dns_packet,test_dns_response)457 ZTEST(dns_packet, test_dns_response)
458 {
459 struct dns_response_test test = {
460 .dname = DNAME1,
461 .res = resp_ipv4,
462 .res_len = sizeof(resp_ipv4),
463 .tid = 0xb041,
464 .answer_type = DNS_RR_TYPE_A,
465 .ancount = 1,
466 .ttl = 3028,
467 .ra = 1,
468 .rd = 1,
469 .rdlen = 4, /* IPv4 test */
470 .rdata = resp_ipv4_addr
471 };
472 struct dns_response_test test1, test2;
473 int rc;
474
475 memcpy(&test1, &test, sizeof(test1));
476 rc = eval_response1(&test1, false);
477 zassert_equal(rc, 0,
478 "Response test failed for domain: " DNAME1
479 " at line %d", -rc);
480
481 /* Test also using dns_unpack_answer() API */
482 memcpy(&test2, &test, sizeof(test2));
483 rc = eval_response1(&test2, true);
484 zassert_equal(rc, 0,
485 "Response test 2 failed for domain: " DNAME1
486 " at line %d", -rc);
487 }
488
489 /* Domain: www.wireshark.org
490 * Type: standard query (IPv4)
491 * Transaction ID: 0x2121
492 * Answer is for a.www.wireshark.org for testing purposes.
493 */
494 char answer_ipv4[] = {
495 0x21, 0x21, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
496 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
497 0x09, 0x77, 0x69, 0x72, 0x65, 0x73, 0x68, 0x61,
498 0x72, 0x6b, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00,
499 0x01, 0x00, 0x01, 0x01, 0x61, 0xc0, 0x0c, 0x00, 0x01, 0x00,
500 0x01, 0x00, 0x00, 0x02, 0x58, 0x00, 0x04, 0xae,
501 0x89, 0x2a, 0x41
502 };
503
504 #define DNAME2 "www.wireshark.org"
505
506 static const uint8_t answer_ipv4_addr[] = { 174, 137, 42, 65 };
507
ZTEST(dns_packet,test_dns_response2)508 ZTEST(dns_packet, test_dns_response2)
509 {
510 struct dns_response_test test1 = {
511 .dname = DNAME2,
512 .res = answer_ipv4,
513 .res_len = sizeof(answer_ipv4),
514 .tid = 0x2121,
515 .answer_type = DNS_RR_TYPE_A,
516 .ancount = 1,
517 .ttl = 600,
518 .ra = 1,
519 .rd = 1,
520 .rdlen = 4, /* IPv4 test */
521 .rdata = answer_ipv4_addr
522 };
523 int rc;
524
525 /* Test also using dns_unpack_answer() API */
526 rc = eval_response1(&test1, true);
527 zassert_equal(rc, 0,
528 "Response test 2 failed for domain: " DNAME2
529 " at line %d", -rc);
530 }
531
ZTEST(dns_packet,test_mdns_query)532 ZTEST(dns_packet, test_mdns_query)
533 {
534 int rc;
535
536 rc = eval_query(ZEPHYR_LOCAL, tid1, DNS_RR_TYPE_A,
537 query_mdns, sizeof(query_mdns));
538 zassert_equal(rc, 0, "Query test failed for domain: " ZEPHYR_LOCAL);
539 }
540
541 /* DNS response for zephyr.local with the following parameters:
542 * Transaction ID: 0xf2b6
543 * Answer type: RR AAAA
544 * Answer counter: 1
545 * TTL: 30
546 * Recursion Available: 0
547 * RD len: 16 (IPv6 Address)
548 * RData: fe80:0000:0000:0000:0200:5eff:fe00:5337
549 */
550 static uint8_t resp_ipv6[] = {
551 0xf2, 0xb6, 0x80, 0x00, 0x00, 0x01, 0x00, 0x01,
552 0x00, 0x00, 0x00, 0x00, 0x06, 0x7a, 0x65, 0x70,
553 0x68, 0x79, 0x72, 0x05, 0x6c, 0x6f, 0x63, 0x61,
554 0x6c, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x06, 0x7a,
555 0x65, 0x70, 0x68, 0x79, 0x72, 0x05, 0x6c, 0x6f,
556 0x63, 0x61, 0x6c, 0x00, 0x00, 0x1c, 0x00, 0x01,
557 0x00, 0x00, 0x00, 0x1e, 0x00, 0x10, 0xfe, 0x80,
558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
559 0x5e, 0xff, 0xfe, 0x00, 0x53, 0x37,
560 };
561
562 static const uint8_t resp_ipv6_addr[] = {
563 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564 0x02, 0x00, 0x5e, 0xff, 0xfe, 0x00, 0x53, 0x37
565 };
566
ZTEST(dns_packet,test_mdns_response)567 ZTEST(dns_packet, test_mdns_response)
568 {
569 struct dns_response_test test1 = {
570 .dname = ZEPHYR_LOCAL,
571 .res = resp_ipv6,
572 .res_len = sizeof(resp_ipv6),
573 .tid = 0xf2b6,
574 .answer_type = DNS_RR_TYPE_AAAA,
575 .ancount = 1,
576 .ttl = 30,
577 .ra = 0,
578 .rd = 0,
579 .rdlen = 16, /* IPv6 test */
580 .rdata = resp_ipv6_addr,
581 };
582 int rc;
583
584 rc = eval_response1(&test1, true);
585 zassert_equal(rc, 0,
586 "Response test failed for domain: " ZEPHYR_LOCAL
587 " at line %d", -rc);
588 }
589
590 static uint8_t resp_truncated_response_ipv4_1[] = {
591 /* DNS msg header (12 bytes) */
592 0xb0, 0x41, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
593 0x00, 0x00, 0x00, 0x00,
594
595 /* Query string (www.zephyrproject.org) */
596 0x03, 0x77, 0x77, 0x77, 0x0d, 0x7a, 0x65, 0x70,
597 0x68, 0x79, 0x72, 0x70, 0x72, 0x6f, 0x6a, 0x65,
598 0x63, 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00,
599
600 /* Query type */
601 0x00, 0x01,
602
603 /* Query class */
604 0x00, 0x01,
605
606 /* Answer data is missing */
607 };
608
609 static uint8_t resp_truncated_response_ipv4_2[] = {
610 /* DNS msg header (12 bytes) */
611 0xb0, 0x41, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
612 0x00, 0x00, 0x00, 0x00,
613
614 /* Query string (www.zephyrproject.org) */
615 0x03, 0x77, 0x77, 0x77, 0x0d, 0x7a, 0x65, 0x70,
616 0x68, 0x79, 0x72, 0x70, 0x72, 0x6f, 0x6a, 0x65,
617 0x63, 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00,
618
619 /* Rest of the data is missing */
620 };
621
622 static uint8_t resp_truncated_response_ipv4_3[] = {
623 /* DNS msg header (12 bytes) */
624 0xb0, 0x41, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
625 0x00, 0x00, 0x00, 0x00,
626
627 /* Query string (www.zephyrproject.org) */
628 0x03, 0x77, 0x77, 0x77, 0x0d, 0x7a, 0x65, 0x70,
629 0x68, 0x79, 0x72, 0x70, 0x72, 0x6f, 0x6a, 0x65,
630 0x63, 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00,
631
632 /* Query type */
633 0x00, 0x01,
634
635 /* Query class */
636 0x00, 0x01,
637
638 /* Answer name */
639 0xc0, 0x1c,
640
641 /* Answer type */
642 0x00, 0x01,
643
644 /* Answer class */
645 0x00, 0x01,
646
647 /* TTL */
648 0x00, 0x00, 0x0b, 0xd4,
649 };
650
651 static uint8_t resp_truncated_response_ipv4_4[] = {
652 /* DNS msg header (12 bytes) */
653 0xb0, 0x41, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
654 0x00, 0x00, 0x00, 0x00,
655
656 /* Query string (www.zephyrproject.org) */
657 0x03, 0x77, 0x77, 0x77, 0x0d, 0x7a, 0x65, 0x70,
658 0x68, 0x79, 0x72, 0x70, 0x72, 0x6f, 0x6a, 0x65,
659 0x63, 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00,
660
661 /* Query type */
662 0x00, 0x01,
663
664 /* Query class */
665 0x00, 0x01,
666
667 /* Answer name */
668 0xc0, 0x1c,
669
670 /* Answer type */
671 0x00, 0x01,
672
673 /* Answer class */
674 0x00, 0x01,
675
676 /* TTL */
677 0x00, 0x00, 0x0b, 0xd4,
678 };
679
680 static uint8_t resp_truncated_response_ipv4_5[] = {
681 /* DNS msg header (12 bytes) */
682 0xb0, 0x41, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
683 0x00, 0x00, 0x00, 0x00,
684
685 /* Query string (www.zephyrproject.org) */
686 0x03, 0x77, 0x77, 0x77, 0x0d, 0x7a, 0x65, 0x70,
687 0x68, 0x79, 0x72, 0x70, 0x72, 0x6f, 0x6a, 0x65,
688 0x63, 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00,
689
690 /* Query type */
691 0x00, 0x01,
692
693 /* Query class */
694 0x00, 0x01,
695
696 /* Answer name */
697 0xc0, 0x1c,
698
699 /* Answer type */
700 0x00, 0x01,
701
702 /* Answer class */
703 0x00, 0x01,
704
705 /* TTL */
706 0x00, 0x00, 0x0b, 0xd4,
707
708 /* Resource data length */
709 0x00, 0x04,
710 };
711
712 static uint8_t resp_valid_response_ipv4_6[] = {
713 /* DNS msg header (12 bytes) */
714 0xb0, 0x41, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
715 0x00, 0x00, 0x00, 0x00,
716
717 /* Query string (www.zephyrproject.org) */
718 0x03, 0x77, 0x77, 0x77, 0x0d, 0x7a, 0x65, 0x70,
719 0x68, 0x79, 0x72, 0x70, 0x72, 0x6f, 0x6a, 0x65,
720 0x63, 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00,
721
722 /* Query type */
723 0x00, 0x01,
724
725 /* Query class */
726 0x00, 0x01,
727
728 /* Answer name */
729 0xc0, 0x1c,
730
731 /* Answer type */
732 0x00, 0x01,
733
734 /* Answer class */
735 0x00, 0x01,
736
737 /* TTL */
738 0x00, 0x00, 0x0b, 0xd4,
739
740 /* Resource data length */
741 0x00, 0x04,
742
743 /* Resource data (IP address) */
744 0x8c, 0xd3, 0xa9, 0x08
745 };
746
747 static uint8_t resp_valid_response_ipv4_7[] = {
748 /* DNS msg header (12 bytes) */
749 0xb0, 0x41, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
750 0x00, 0x00, 0x00, 0x00,
751
752 /* Query string (www.zephyrproject.org) */
753 0x03, 0x77, 0x77, 0x77, 0x0d, 0x7a, 0x65, 0x70,
754 0x68, 0x79, 0x72, 0x70, 0x72, 0x6f, 0x6a, 0x65,
755 0x63, 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00,
756
757 /* Query type */
758 0x00, 0x01,
759
760 /* Query class */
761 0x00, 0x01,
762
763 /* Answer name (do not use pointer here) */
764 0x03, 0x77, 0x77, 0x77, 0x0d, 0x7a, 0x65, 0x70,
765 0x68, 0x79, 0x72, 0x70, 0x72, 0x6f, 0x6a, 0x65,
766 0x63, 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00,
767
768 /* Answer type */
769 0x00, 0x01,
770
771 /* Answer class */
772 0x00, 0x01,
773
774 /* TTL */
775 0x00, 0x00, 0x0b, 0xd4,
776
777 /* Resource data length */
778 0x00, 0x04,
779
780 /* Resource data (IP address) */
781 0x8c, 0xd3, 0xa9, 0x08
782 };
783
784 static uint8_t resp_valid_response_ipv4_8[] = {
785 /* DNS msg header (12 bytes) */
786 0xb0, 0x41, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
787 0x00, 0x00, 0x00, 0x00,
788
789 /* Query string (www.zephyrproject.org) */
790 0x03, 0x77, 0x77, 0x77, 0x0d, 0x7a, 0x65, 0x70,
791 0x68, 0x79, 0x72, 0x70, 0x72, 0x6f, 0x6a, 0x65,
792 0x63, 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00,
793
794 /* Query type */
795 0x00, 0x01,
796
797 /* Query class */
798 0x00, 0x01,
799
800 /* 1st answer name (do not use pointer here) */
801 0x03, 0x77, 0x77, 0x77, 0x0d, 0x7a, 0x65, 0x70,
802 0x68, 0x79, 0x72, 0x70, 0x72, 0x6f, 0x6a, 0x65,
803 0x63, 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00,
804
805 /* Answer type */
806 0x00, 0x01,
807
808 /* Answer class */
809 0x00, 0x01,
810
811 /* TTL */
812 0x00, 0x00, 0x0b, 0xd4,
813
814 /* Resource data length */
815 0x00, 0x04,
816
817 /* Resource data (IP address) */
818 0x8c, 0xd3, 0xa9, 0x08,
819
820 /* 2nd answer name (do not use pointer here) */
821 0x03, 0x77, 0x77, 0x77, 0x0d, 0x7a, 0x65, 0x70,
822 0x68, 0x79, 0x72, 0x70, 0x72, 0x6f, 0x6a, 0x65,
823 0x63, 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00,
824
825 /* Answer type */
826 0x00, 0x01,
827
828 /* Answer class */
829 0x00, 0x01,
830
831 /* TTL */
832 0x00, 0x00, 0x0b, 0xd4,
833
834 /* Resource data length */
835 0x00, 0x04,
836
837 /* Resource data (IP address) */
838 0x8c, 0xd3, 0xa9, 0x09
839 };
840
841 static uint8_t resp_valid_response_ipv4_9[] = {
842 /* DNS msg header (12 bytes) */
843 0xb0, 0x41, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
844 0x00, 0x00, 0x00, 0x00,
845
846 /* Query string (www.zephyrproject.org) */
847 0x03, 0x77, 0x77, 0x77, 0x0d, 0x7a, 0x65, 0x70,
848 0x68, 0x79, 0x72, 0x70, 0x72, 0x6f, 0x6a, 0x65,
849 0x63, 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00,
850
851 /* Query type */
852 0x00, 0x01,
853
854 /* Query class */
855 0x00, 0x01,
856
857 /* 1st answer name (use pointer for 1st answer) */
858 0xc0, 0x1c,
859
860 /* Answer type */
861 0x00, 0x01,
862
863 /* Answer class */
864 0x00, 0x01,
865
866 /* TTL */
867 0x00, 0x00, 0x0b, 0xd4,
868
869 /* Resource data length */
870 0x00, 0x04,
871
872 /* Resource data (IP address) */
873 0x8c, 0xd3, 0xa9, 0x08,
874
875 /* 2nd answer name (do not use pointer here) */
876 0x03, 0x77, 0x77, 0x77, 0x0d, 0x7a, 0x65, 0x70,
877 0x68, 0x79, 0x72, 0x70, 0x72, 0x6f, 0x6a, 0x65,
878 0x63, 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00,
879
880 /* Answer type */
881 0x00, 0x01,
882
883 /* Answer class */
884 0x00, 0x01,
885
886 /* TTL */
887 0x00, 0x00, 0x0b, 0xd4,
888
889 /* Resource data length */
890 0x00, 0x04,
891
892 /* Resource data (IP address) */
893 0x8c, 0xd3, 0xa9, 0x09
894 };
895
896 static uint8_t resp_valid_response_ipv4_10[] = {
897 /* DNS msg header (12 bytes) */
898 0x74, 0xe1, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
899 0x00, 0x00, 0x00, 0x00,
900
901 /* Query string */
902 0x0e, 0x77, 0x65, 0x73, 0x74, 0x75, 0x73, 0x32,
903 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x2d, 0x32, 0x0d,
904 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
905 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x05, 0x74, 0x65,
906 0x61, 0x6d, 0x73, 0x09, 0x6d, 0x69, 0x63, 0x72,
907 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x03, 0x63, 0x6f,
908 0x6d, 0x00,
909
910 /* Type */
911 0x00, 0x01,
912
913 /* Class */
914 0x00, 0x01,
915
916 /* Answer 1 */
917 0xc0, 0x0c,
918
919 /* Answer type (cname) */
920 0x00, 0x05,
921
922 /* Class */
923 0x00, 0x01,
924
925 /* TTL */
926 0x00, 0x00, 0x00, 0x04,
927
928 /* RR data length */
929 0x00, 0x26,
930
931 /* Data */
932 0x11, 0x77, 0x65, 0x73, 0x74, 0x75, 0x73, 0x32,
933 0x63, 0x6e, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x64,
934 0x2d, 0x32, 0x0e, 0x74, 0x72, 0x61, 0x66, 0x66,
935 0x69, 0x63, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
936 0x72, 0x03, 0x6e, 0x65, 0x74, 0x00,
937
938 /* Answer 2 */
939 0xc0, 0x4e,
940
941 /* cname */
942 0x00, 0x05,
943
944 /* Class */
945 0x00, 0x01,
946
947 /* TTL */
948 0x00, 0x00, 0x00, 0x04,
949
950 /* RR data length */
951 0x00, 0x2e,
952
953 /* Data */
954 0x14, 0x77, 0x65, 0x73, 0x74, 0x75, 0x73, 0x32,
955 0x63, 0x6e, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x64,
956 0x2d, 0x32, 0x2d, 0x31, 0x36, 0x07, 0x77, 0x65,
957 0x73, 0x74, 0x75, 0x73, 0x32, 0x08, 0x63, 0x6c,
958 0x6f, 0x75, 0x64, 0x61, 0x70, 0x70, 0x05, 0x61,
959 0x7a, 0x75, 0x72, 0x65, 0xc0, 0x39,
960 };
961
962 static uint8_t resp_valid_response_ipv4_11[] = {
963 /* DNS msg header (12 bytes) */
964 0x74, 0xe1, 0x81, 0x80, 0x00, 0x01, 0x00, 0x03,
965 0x00, 0x00, 0x00, 0x00,
966
967 /* Query string */
968 0x0e, 0x77, 0x65, 0x73, 0x74, 0x75, 0x73, 0x32,
969 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x2d, 0x32, 0x0d,
970 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
971 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x05, 0x74, 0x65,
972 0x61, 0x6d, 0x73, 0x09, 0x6d, 0x69, 0x63, 0x72,
973 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x03, 0x63, 0x6f,
974 0x6d, 0x00,
975
976 /* Type */
977 0x00, 0x01,
978
979 /* Class */
980 0x00, 0x01,
981
982 /* Answer 1 */
983 0xc0, 0x0c,
984
985 /* Answer type (cname) */
986 0x00, 0x05,
987
988 /* Class */
989 0x00, 0x01,
990
991 /* TTL */
992 0x00, 0x00, 0x00, 0x04,
993
994 /* RR data length */
995 0x00, 0x26,
996
997 /* Data */
998 0x11, 0x77, 0x65, 0x73, 0x74, 0x75, 0x73, 0x32,
999 0x63, 0x6e, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x64,
1000 0x2d, 0x32, 0x0e, 0x74, 0x72, 0x61, 0x66, 0x66,
1001 0x69, 0x63, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
1002 0x72, 0x03, 0x6e, 0x65, 0x74, 0x00,
1003
1004 /* Answer 2 */
1005 0xc0, 0x4e,
1006
1007 /* cname */
1008 0x00, 0x05,
1009
1010 /* Class */
1011 0x00, 0x01,
1012
1013 /* TTL */
1014 0x00, 0x00, 0x00, 0x04,
1015
1016 /* RR data length */
1017 0x00, 0x2e,
1018
1019 /* Data */
1020 0x14, 0x77, 0x65, 0x73, 0x74, 0x75, 0x73, 0x32,
1021 0x63, 0x6e, 0x73, 0x2d, 0x70, 0x72, 0x6f, 0x64,
1022 0x2d, 0x32, 0x2d, 0x31, 0x36, 0x07, 0x77, 0x65,
1023 0x73, 0x74, 0x75, 0x73, 0x32, 0x08, 0x63, 0x6c,
1024 0x6f, 0x75, 0x64, 0x61, 0x70, 0x70, 0x05, 0x61,
1025 0x7a, 0x75, 0x72, 0x65, 0xc0, 0x39,
1026
1027 /* Answer 3 */
1028 0xc0, 0x80,
1029
1030 /* A record */
1031 0x00, 0x01,
1032
1033 /* Class */
1034 0x00, 0x01,
1035
1036 /* TTL */
1037 0x00, 0x00, 0x00, 0x04,
1038
1039 /* RR length */
1040 0x00, 0x04,
1041
1042 /* IP address */
1043 0x34, 0x72, 0x94, 0x90
1044 };
1045
resolve_cb(enum dns_resolve_status status,struct dns_addrinfo * info,void * user_data)1046 static void resolve_cb(enum dns_resolve_status status,
1047 struct dns_addrinfo *info,
1048 void *user_data)
1049 {
1050 ARG_UNUSED(status);
1051 ARG_UNUSED(info);
1052 ARG_UNUSED(user_data);
1053 }
1054
setup_dns_context(struct dns_resolve_context * ctx,int idx,uint16_t dns_id,const uint8_t * query,size_t query_len,enum dns_query_type query_type)1055 static void setup_dns_context(struct dns_resolve_context *ctx,
1056 int idx,
1057 uint16_t dns_id,
1058 const uint8_t *query,
1059 size_t query_len,
1060 enum dns_query_type query_type)
1061 {
1062 ctx->queries[idx].cb = resolve_cb;
1063 ctx->queries[idx].id = dns_id;
1064 ctx->queries[idx].query = query;
1065 ctx->queries[idx].query_type = query_type;
1066 ctx->queries[idx].query_hash = crc16_ansi(query, query_len);
1067 ctx->state = DNS_RESOLVE_CONTEXT_ACTIVE;
1068
1069 }
1070
run_dns_malformed_response(const char * test_case,uint8_t * buf,size_t len)1071 static void run_dns_malformed_response(const char *test_case,
1072 uint8_t *buf, size_t len)
1073 {
1074 /* Query is used to calculate the hash, it contains the
1075 * labels + query type
1076 */
1077 static const uint8_t query[] = {
1078 /* Labels */
1079 0x03, 0x77, 0x77, 0x77, 0x0d, 0x7a, 0x65, 0x70,
1080 0x68, 0x79, 0x72, 0x70, 0x72, 0x6f, 0x6a, 0x65,
1081 0x63, 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00,
1082 /* Query type */
1083 0x00, 0x01
1084 };
1085 struct dns_msg_t dns_msg = { 0 };
1086 uint16_t dns_id = 0;
1087 int query_idx = -1;
1088 uint16_t query_hash = 0;
1089 int ret;
1090
1091 dns_msg.msg = buf;
1092 dns_msg.msg_size = len;
1093
1094 dns_id = dns_unpack_header_id(dns_msg.msg);
1095
1096 setup_dns_context(&dns_ctx, 0, dns_id, query, sizeof(query),
1097 DNS_QUERY_TYPE_A);
1098
1099 ret = dns_validate_msg(&dns_ctx, &dns_msg, &dns_id, &query_idx,
1100 NULL, &query_hash);
1101 zassert_not_equal(ret, DNS_EAI_ALLDONE,
1102 "[%s] DNS message was valid (%d)",
1103 test_case, ret);
1104 }
1105
run_dns_valid_response(const char * test_case,uint8_t * buf,size_t len)1106 static void run_dns_valid_response(const char *test_case,
1107 uint8_t *buf, size_t len)
1108 {
1109 struct dns_msg_t dns_msg = { 0 };
1110 uint16_t dns_id = 0;
1111 int query_idx = -1;
1112 uint16_t query_hash = 0;
1113 int ret;
1114
1115 dns_msg.msg = buf;
1116 dns_msg.msg_size = len;
1117
1118 ret = dns_validate_msg(&dns_ctx, &dns_msg, &dns_id, &query_idx,
1119 NULL, &query_hash);
1120 zassert_equal(ret, DNS_EAI_ALLDONE, "[%s] DNS message failed (%d)",
1121 test_case, ret);
1122 }
1123
1124 #define DNS_RESOLVER_MAX_BUF_SIZE 512
1125 #define DNS_RESOLVER_MIN_BUF 1
1126 #define DNS_RESOLVER_BUF_CTR (DNS_RESOLVER_MIN_BUF + 1)
1127 #define DNS_MAX_NAME_LEN 255
1128
1129 NET_BUF_POOL_DEFINE(dns_qname_pool, DNS_RESOLVER_BUF_CTR, DNS_MAX_NAME_LEN,
1130 0, NULL);
1131
run_dns_valid_cname_response(const char * test_case,uint8_t * buf,size_t len,int expected_ret)1132 static void run_dns_valid_cname_response(const char *test_case,
1133 uint8_t *buf, size_t len,
1134 int expected_ret)
1135 {
1136 static const uint8_t query[] = {
1137 /* Query string */
1138 0x0e, 0x77, 0x65, 0x73, 0x74, 0x75, 0x73, 0x32,
1139 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x2d, 0x32, 0x0d,
1140 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
1141 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x05, 0x74, 0x65,
1142 0x61, 0x6d, 0x73, 0x09, 0x6d, 0x69, 0x63, 0x72,
1143 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x03, 0x63, 0x6f,
1144 0x6d, 0x00,
1145
1146 /* Type */
1147 0x00, 0x01,
1148 };
1149 struct dns_msg_t dns_msg = { 0 };
1150 struct net_buf *dns_cname;
1151 uint16_t dns_id = 0;
1152 int query_idx = -1;
1153 uint16_t query_hash = 0;
1154 int ret;
1155
1156 dns_msg.msg = buf;
1157 dns_msg.msg_size = len;
1158
1159 dns_cname = net_buf_alloc(&dns_qname_pool, K_MSEC(100));
1160 zassert_not_null(dns_cname, "Out of mem");
1161
1162 dns_id = dns_unpack_header_id(dns_msg.msg);
1163
1164 setup_dns_context(&dns_ctx, 0, dns_id, query, sizeof(query),
1165 DNS_QUERY_TYPE_A);
1166
1167 ret = dns_validate_msg(&dns_ctx, &dns_msg, &dns_id, &query_idx,
1168 dns_cname, &query_hash);
1169 zassert_equal(ret, expected_ret, "[%s] DNS message failed (%d)",
1170 test_case, ret);
1171 }
1172
1173 #define RUN_VALID_TEST(test_name) \
1174 run_dns_valid_response(#test_name, test_name, sizeof(test_name))
1175
1176 #define RUN_VALID_CNAME_TEST(test_name, expected_ret) \
1177 run_dns_valid_cname_response(#test_name, test_name, \
1178 sizeof(test_name), expected_ret)
1179
test_dns_valid_responses(void)1180 static void test_dns_valid_responses(void)
1181 {
1182 RUN_VALID_TEST(resp_valid_response_ipv4_6);
1183 RUN_VALID_TEST(resp_valid_response_ipv4_7);
1184 RUN_VALID_TEST(resp_valid_response_ipv4_8);
1185 RUN_VALID_TEST(resp_valid_response_ipv4_9);
1186
1187 RUN_VALID_CNAME_TEST(resp_valid_response_ipv4_10, DNS_EAI_AGAIN);
1188 RUN_VALID_CNAME_TEST(resp_valid_response_ipv4_11, DNS_EAI_ALLDONE);
1189 }
1190
1191 #define RUN_MALFORMED_TEST(test_name) \
1192 run_dns_malformed_response(#test_name, test_name, sizeof(test_name))
1193
test_dns_malformed_responses(void)1194 static void test_dns_malformed_responses(void)
1195 {
1196 RUN_MALFORMED_TEST(resp_truncated_response_ipv4_1);
1197 RUN_MALFORMED_TEST(resp_truncated_response_ipv4_2);
1198 RUN_MALFORMED_TEST(resp_truncated_response_ipv4_3);
1199 RUN_MALFORMED_TEST(resp_truncated_response_ipv4_4);
1200 RUN_MALFORMED_TEST(resp_truncated_response_ipv4_5);
1201 }
1202
ZTEST(dns_packet,test_dns_malformed_and_valid_responses)1203 ZTEST(dns_packet, test_dns_malformed_and_valid_responses)
1204 {
1205 test_dns_malformed_responses();
1206 test_dns_valid_responses();
1207 }
1208
ZTEST(dns_packet,test_dns_id_len)1209 ZTEST(dns_packet, test_dns_id_len)
1210 {
1211 struct dns_msg_t dns_msg = { 0 };
1212 uint8_t buf[1];
1213 uint16_t dns_id = 0;
1214 int query_idx = -1;
1215 uint16_t query_hash = 0;
1216 int ret;
1217
1218 dns_msg.msg = buf;
1219 dns_msg.msg_size = sizeof(buf);
1220
1221 ret = dns_validate_msg(&dns_ctx, &dns_msg, &dns_id, &query_idx,
1222 NULL, &query_hash);
1223 zassert_equal(ret, DNS_EAI_FAIL,
1224 "DNS message length check failed (%d)", ret);
1225 }
1226
ZTEST(dns_packet,test_dns_flags_len)1227 ZTEST(dns_packet, test_dns_flags_len)
1228 {
1229 struct dns_msg_t dns_msg = { 0 };
1230 uint8_t buf[3];
1231 uint16_t dns_id = 0;
1232 int query_idx = -1;
1233 uint16_t query_hash = 0;
1234 int ret;
1235
1236 dns_msg.msg = buf;
1237 dns_msg.msg_size = sizeof(buf);
1238
1239 ret = dns_validate_msg(&dns_ctx, &dns_msg, &dns_id, &query_idx,
1240 NULL, &query_hash);
1241 zassert_equal(ret, DNS_EAI_FAIL,
1242 "DNS message length check failed (%d)", ret);
1243 }
1244
1245 ZTEST_SUITE(dns_packet, NULL, NULL, NULL, NULL, NULL);
1246 /* TODO:
1247 * 1) add malformed DNS data (mostly done)
1248 * 2) add validations against buffer overflows
1249 * 3) add debug info to detect the exit point (or split the tests)
1250 * 4) add test data with CNAME and more RR
1251 */
1252