]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-packet.c
resolved: TXT records
[thirdparty/systemd.git] / src / resolve / resolved-dns-packet.c
CommitLineData
74b2466e
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22#include "utf8.h"
c73ce96b 23#include "util.h"
2e276efc 24#include "strv.h"
74b2466e
LP
25#include "resolved-dns-domain.h"
26#include "resolved-dns-packet.h"
27
1716f6dc 28int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
74b2466e
LP
29 DnsPacket *p;
30 size_t a;
31
32 assert(ret);
33
34 if (mtu <= 0)
35 a = DNS_PACKET_SIZE_START;
36 else
37 a = mtu;
38
39 if (a < DNS_PACKET_HEADER_SIZE)
40 a = DNS_PACKET_HEADER_SIZE;
41
c73ce96b
LP
42 /* round up to next page size */
43 a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket));
44
45 /* make sure we never allocate more than useful */
46 if (a > DNS_PACKET_SIZE_MAX)
47 a = DNS_PACKET_SIZE_MAX;
48
74b2466e
LP
49 p = malloc0(ALIGN(sizeof(DnsPacket)) + a);
50 if (!p)
51 return -ENOMEM;
52
53 p->size = p->rindex = DNS_PACKET_HEADER_SIZE;
54 p->allocated = a;
1716f6dc 55 p->protocol = protocol;
74b2466e
LP
56 p->n_ref = 1;
57
58 *ret = p;
59
60 return 0;
61}
62
1716f6dc 63int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
74b2466e
LP
64 DnsPacket *p;
65 DnsPacketHeader *h;
66 int r;
67
68 assert(ret);
69
1716f6dc 70 r = dns_packet_new(&p, protocol, mtu);
74b2466e
LP
71 if (r < 0)
72 return r;
73
74 h = DNS_PACKET_HEADER(p);
1716f6dc 75
ea917db9
LP
76 if (protocol == DNS_PROTOCOL_LLMNR)
77 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,
78 0 /* opcode */,
79 0 /* c */,
80 0 /* tc */,
81 0 /* t */,
82 0 /* ra */,
83 0 /* ad */,
84 0 /* cd */,
85 0 /* rcode */));
1716f6dc 86 else
ea917db9
LP
87 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,
88 0 /* opcode */,
89 0 /* aa */,
90 0 /* tc */,
91 1 /* rd (ask for recursion) */,
92 0 /* ra */,
93 0 /* ad */,
94 0 /* cd */,
95 0 /* rcode */));
74b2466e
LP
96
97 *ret = p;
98 return 0;
99}
100
101DnsPacket *dns_packet_ref(DnsPacket *p) {
102
103 if (!p)
104 return NULL;
105
106 assert(p->n_ref > 0);
107 p->n_ref++;
108 return p;
109}
110
111static void dns_packet_free(DnsPacket *p) {
112 char *s;
113
114 assert(p);
115
faa133f3
LP
116 dns_question_unref(p->question);
117 dns_answer_unref(p->answer);
322345fd 118
74b2466e
LP
119 while ((s = hashmap_steal_first_key(p->names)))
120 free(s);
121 hashmap_free(p->names);
122
faa133f3 123 free(p->_data);
74b2466e
LP
124 free(p);
125}
126
127DnsPacket *dns_packet_unref(DnsPacket *p) {
128 if (!p)
129 return NULL;
130
131 assert(p->n_ref > 0);
132
133 if (p->n_ref == 1)
134 dns_packet_free(p);
135 else
136 p->n_ref--;
137
138 return NULL;
139}
140
141int dns_packet_validate(DnsPacket *p) {
142 assert(p);
143
144 if (p->size < DNS_PACKET_HEADER_SIZE)
145 return -EBADMSG;
146
c73ce96b
LP
147 if (p->size > DNS_PACKET_SIZE_MAX)
148 return -EBADMSG;
149
623a4c97 150 return 1;
74b2466e
LP
151}
152
153int dns_packet_validate_reply(DnsPacket *p) {
74b2466e
LP
154 int r;
155
156 assert(p);
157
158 r = dns_packet_validate(p);
159 if (r < 0)
160 return r;
161
623a4c97
LP
162 if (DNS_PACKET_QR(p) != 1)
163 return 0;
164
165 if (DNS_PACKET_OPCODE(p) != 0)
74b2466e
LP
166 return -EBADMSG;
167
ea917db9
LP
168 /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */
169 if (p->protocol == DNS_PROTOCOL_LLMNR &&
170 DNS_PACKET_QDCOUNT(p) != 1)
171 return -EBADMSG;
172
623a4c97
LP
173 return 1;
174}
175
176int dns_packet_validate_query(DnsPacket *p) {
177 int r;
178
179 assert(p);
180
181 r = dns_packet_validate(p);
182 if (r < 0)
183 return r;
184
185 if (DNS_PACKET_QR(p) != 0)
186 return 0;
187
3cb10d3a 188 if (DNS_PACKET_OPCODE(p) != 0)
74b2466e
LP
189 return -EBADMSG;
190
623a4c97
LP
191 if (DNS_PACKET_TC(p))
192 return -EBADMSG;
193
ea917db9 194 /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */
623a4c97
LP
195 if (p->protocol == DNS_PROTOCOL_LLMNR &&
196 DNS_PACKET_QDCOUNT(p) != 1)
197 return -EBADMSG;
198
ea917db9 199 /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */
623a4c97
LP
200 if (DNS_PACKET_ANCOUNT(p) > 0)
201 return -EBADMSG;
202
ea917db9 203 /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */
623a4c97
LP
204 if (DNS_PACKET_NSCOUNT(p) > 0)
205 return -EBADMSG;
206
207 return 1;
74b2466e
LP
208}
209
210static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
211 assert(p);
212
c73ce96b
LP
213 if (p->size + add > p->allocated) {
214 size_t a;
215
216 a = PAGE_ALIGN((p->size + add) * 2);
217 if (a > DNS_PACKET_SIZE_MAX)
218 a = DNS_PACKET_SIZE_MAX;
219
220 if (p->size + add > a)
221 return -EMSGSIZE;
222
faa133f3 223 if (p->_data) {
c73ce96b
LP
224 void *d;
225
faa133f3 226 d = realloc(p->_data, a);
c73ce96b
LP
227 if (!d)
228 return -ENOMEM;
229
faa133f3 230 p->_data = d;
c73ce96b 231 } else {
faa133f3
LP
232 p->_data = malloc(a);
233 if (!p->_data)
c73ce96b
LP
234 return -ENOMEM;
235
faa133f3
LP
236 memcpy(p->_data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size);
237 memzero((uint8_t*) p->_data + p->size, a - p->size);
c73ce96b
LP
238 }
239
240 p->allocated = a;
241 }
74b2466e
LP
242
243 if (start)
244 *start = p->size;
245
246 if (ret)
247 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size;
248
249 p->size += add;
250 return 0;
251}
252
253static void dns_packet_truncate(DnsPacket *p, size_t sz) {
254 Iterator i;
255 char *s;
256 void *n;
257
258 assert(p);
259
260 if (p->size <= sz)
261 return;
262
263 HASHMAP_FOREACH_KEY(s, n, p->names, i) {
264
265 if (PTR_TO_SIZE(n) < sz)
266 continue;
267
268 hashmap_remove(p->names, s);
269 free(s);
270 }
271
272 p->size = sz;
273}
274
623a4c97
LP
275int dns_packet_append_blob(DnsPacket *p, const void *d, size_t l, size_t *start) {
276 void *q;
277 int r;
278
279 assert(p);
280
281 r = dns_packet_extend(p, l, &q, start);
282 if (r < 0)
283 return r;
284
285 memcpy(q, d, l);
286 return 0;
287}
288
74b2466e
LP
289int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) {
290 void *d;
291 int r;
292
293 assert(p);
294
295 r = dns_packet_extend(p, sizeof(uint8_t), &d, start);
296 if (r < 0)
297 return r;
298
299 ((uint8_t*) d)[0] = v;
300
301 return 0;
302}
303
304int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
305 void *d;
306 int r;
307
308 assert(p);
309
310 r = dns_packet_extend(p, sizeof(uint16_t), &d, start);
311 if (r < 0)
312 return r;
313
314 ((uint8_t*) d)[0] = (uint8_t) (v >> 8);
623a4c97
LP
315 ((uint8_t*) d)[1] = (uint8_t) v;
316
317 return 0;
318}
319
320int dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start) {
321 void *d;
322 int r;
323
324 assert(p);
325
326 r = dns_packet_extend(p, sizeof(uint32_t), &d, start);
327 if (r < 0)
328 return r;
329
330 ((uint8_t*) d)[0] = (uint8_t) (v >> 24);
331 ((uint8_t*) d)[1] = (uint8_t) (v >> 16);
332 ((uint8_t*) d)[2] = (uint8_t) (v >> 8);
333 ((uint8_t*) d)[3] = (uint8_t) v;
74b2466e
LP
334
335 return 0;
336}
337
338int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
339 void *d;
340 size_t l;
341 int r;
342
343 assert(p);
344 assert(s);
345
346 l = strlen(s);
347 if (l > 255)
348 return -E2BIG;
349
350 r = dns_packet_extend(p, 1 + l, &d, start);
351 if (r < 0)
352 return r;
353
354 ((uint8_t*) d)[0] = (uint8_t) l;
355 memcpy(((uint8_t*) d) + 1, s, l);
356
357 return 0;
358}
359
360int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
361 void *w;
362 int r;
363
364 assert(p);
365 assert(d);
366
367 if (l > DNS_LABEL_MAX)
368 return -E2BIG;
369
370 r = dns_packet_extend(p, 1 + l, &w, start);
371 if (r < 0)
372 return r;
373
374 ((uint8_t*) w)[0] = (uint8_t) l;
375 memcpy(((uint8_t*) w) + 1, d, l);
376
377 return 0;
378}
379
380int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
381 size_t saved_size;
382 int r;
383
384 assert(p);
385 assert(name);
386
387 saved_size = p->size;
388
389 while (*name) {
390 _cleanup_free_ char *s = NULL;
391 char label[DNS_LABEL_MAX];
392 size_t n;
393
394 n = PTR_TO_SIZE(hashmap_get(p->names, name));
395 if (n > 0) {
396 assert(n < p->size);
397
398 if (n < 0x4000) {
399 r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
400 if (r < 0)
401 goto fail;
402
403 goto done;
404 }
405 }
406
407 s = strdup(name);
408 if (!s) {
409 r = -ENOMEM;
410 goto fail;
411 }
412
413 r = dns_label_unescape(&name, label, sizeof(label));
414 if (r < 0)
415 goto fail;
416
417 r = dns_packet_append_label(p, label, r, &n);
418 if (r < 0)
419 goto fail;
420
421 r = hashmap_ensure_allocated(&p->names, dns_name_hash_func, dns_name_compare_func);
422 if (r < 0)
423 goto fail;
424
425 r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
426 if (r < 0)
427 goto fail;
428
429 s = NULL;
430 }
431
432 r = dns_packet_append_uint8(p, 0, NULL);
433 if (r < 0)
434 return r;
435
436done:
437 if (start)
438 *start = saved_size;
439
440 return 0;
441
442fail:
443 dns_packet_truncate(p, saved_size);
444 return r;
445}
446
447int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
448 size_t saved_size;
449 int r;
450
451 assert(p);
452 assert(k);
453
454 saved_size = p->size;
455
faa133f3 456 r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), NULL);
74b2466e
LP
457 if (r < 0)
458 goto fail;
459
460 r = dns_packet_append_uint16(p, k->type, NULL);
461 if (r < 0)
462 goto fail;
463
464 r = dns_packet_append_uint16(p, k->class, NULL);
465 if (r < 0)
466 goto fail;
467
468 if (start)
469 *start = saved_size;
470
471 return 0;
472
473fail:
474 dns_packet_truncate(p, saved_size);
475 return r;
476}
477
623a4c97
LP
478int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) {
479 size_t saved_size, rdlength_offset, end, rdlength;
480 int r;
481
482 assert(p);
483 assert(rr);
484
485 saved_size = p->size;
486
487 r = dns_packet_append_key(p, rr->key, NULL);
488 if (r < 0)
489 goto fail;
490
491 r = dns_packet_append_uint32(p, rr->ttl, NULL);
492 if (r < 0)
493 goto fail;
494
495 /* Initially we write 0 here */
496 r = dns_packet_append_uint16(p, 0, &rdlength_offset);
497 if (r < 0)
498 goto fail;
499
500 switch (rr->key->type) {
501
502 case DNS_TYPE_PTR:
503 case DNS_TYPE_NS:
504 case DNS_TYPE_CNAME:
505 r = dns_packet_append_name(p, rr->ptr.name, NULL);
506 break;
507
508 case DNS_TYPE_HINFO:
509 r = dns_packet_append_string(p, rr->hinfo.cpu, NULL);
510 if (r < 0)
511 goto fail;
512
513 r = dns_packet_append_string(p, rr->hinfo.os, NULL);
514 break;
515
2e276efc
ZJS
516 case DNS_TYPE_TXT: {
517 char **s;
518
519 STRV_FOREACH(s, rr->txt.strings) {
520 r = dns_packet_append_string(p, *s, NULL);
521 if (r < 0)
522 goto fail;
523 }
524
525 break;
526 }
527
623a4c97
LP
528 case DNS_TYPE_A:
529 r = dns_packet_append_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
530 break;
531
532 case DNS_TYPE_AAAA:
533 r = dns_packet_append_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
534 break;
535
536 case DNS_TYPE_SOA:
537 r = dns_packet_append_name(p, rr->soa.mname, NULL);
538 if (r < 0)
539 goto fail;
540
541 r = dns_packet_append_name(p, rr->soa.rname, NULL);
542 if (r < 0)
543 goto fail;
544
545 r = dns_packet_append_uint32(p, rr->soa.serial, NULL);
546 if (r < 0)
547 goto fail;
548
549 r = dns_packet_append_uint32(p, rr->soa.refresh, NULL);
550 if (r < 0)
551 goto fail;
552
553 r = dns_packet_append_uint32(p, rr->soa.retry, NULL);
554 if (r < 0)
555 goto fail;
556
557 r = dns_packet_append_uint32(p, rr->soa.expire, NULL);
558 if (r < 0)
559 goto fail;
560
561 r = dns_packet_append_uint32(p, rr->soa.minimum, NULL);
562 break;
563
564 case DNS_TYPE_MX:
946c7094
ZJS
565 r = dns_packet_append_uint16(p, rr->mx.priority, NULL);
566 if (r < 0)
567 goto fail;
568
569 r = dns_packet_append_name(p, rr->mx.exchange, NULL);
570 break;
571
623a4c97
LP
572 case DNS_TYPE_SRV:
573 case DNS_TYPE_DNAME:
574 case DNS_TYPE_SSHFP:
575 default:
576 r = dns_packet_append_blob(p, rr->generic.data, rr->generic.size, NULL);
577 break;
578 }
579 if (r < 0)
580 goto fail;
581
582 /* Let's calculate the actual data size and update the field */
583 rdlength = p->size - rdlength_offset - sizeof(uint16_t);
584 if (rdlength > 0xFFFF) {
585 r = ENOSPC;
586 goto fail;
587 }
588
589 end = p->size;
590 p->size = rdlength_offset;
591 r = dns_packet_append_uint16(p, rdlength, NULL);
592 if (r < 0)
593 goto fail;
594 p->size = end;
595
351e6342
LP
596 if (start)
597 *start = saved_size;
598
623a4c97
LP
599 return 0;
600
601fail:
602 dns_packet_truncate(p, saved_size);
603 return r;
604}
605
606
74b2466e
LP
607int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
608 assert(p);
609
610 if (p->rindex + sz > p->size)
611 return -EMSGSIZE;
612
613 if (ret)
614 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
615
616 if (start)
617 *start = p->rindex;
618
619 p->rindex += sz;
620 return 0;
621}
622
8ba9fd9c 623void dns_packet_rewind(DnsPacket *p, size_t idx) {
74b2466e
LP
624 assert(p);
625 assert(idx <= p->size);
626 assert(idx >= DNS_PACKET_HEADER_SIZE);
627
628 p->rindex = idx;
629}
630
623a4c97
LP
631int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start) {
632 const void *q;
633 int r;
634
635 assert(p);
636 assert(d);
637
638 r = dns_packet_read(p, sz, &q, start);
639 if (r < 0)
640 return r;
641
642 memcpy(d, q, sz);
643 return 0;
644}
645
74b2466e
LP
646int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
647 const void *d;
648 int r;
649
650 assert(p);
651
652 r = dns_packet_read(p, sizeof(uint8_t), &d, start);
653 if (r < 0)
654 return r;
655
656 *ret = ((uint8_t*) d)[0];
657 return 0;
658}
659
660int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
661 const void *d;
662 int r;
663
664 assert(p);
665
666 r = dns_packet_read(p, sizeof(uint16_t), &d, start);
667 if (r < 0)
668 return r;
669
670 *ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) |
671 ((uint16_t) ((uint8_t*) d)[1]);
672 return 0;
673}
674
675int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
676 const void *d;
677 int r;
678
679 assert(p);
680
681 r = dns_packet_read(p, sizeof(uint32_t), &d, start);
682 if (r < 0)
683 return r;
684
685 *ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) |
686 (((uint32_t) ((uint8_t*) d)[1]) << 16) |
687 (((uint32_t) ((uint8_t*) d)[2]) << 8) |
688 ((uint32_t) ((uint8_t*) d)[3]);
689
690 return 0;
691}
692
693int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
694 size_t saved_rindex;
695 const void *d;
696 char *t;
697 uint8_t c;
698 int r;
699
700 assert(p);
701
702 saved_rindex = p->rindex;
703
704 r = dns_packet_read_uint8(p, &c, NULL);
705 if (r < 0)
706 goto fail;
707
708 r = dns_packet_read(p, c, &d, NULL);
709 if (r < 0)
710 goto fail;
711
712 if (memchr(d, 0, c)) {
713 r = -EBADMSG;
714 goto fail;
715 }
716
717 t = strndup(d, c);
718 if (!t) {
719 r = -ENOMEM;
720 goto fail;
721 }
722
723 if (!utf8_is_valid(t)) {
724 free(t);
725 r = -EBADMSG;
726 goto fail;
727 }
728
729 *ret = t;
730
731 if (start)
732 *start = saved_rindex;
733
734 return 0;
735
736fail:
737 dns_packet_rewind(p, saved_rindex);
738 return r;
739}
740
741int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
742 size_t saved_rindex, after_rindex = 0;
743 _cleanup_free_ char *ret = NULL;
744 size_t n = 0, allocated = 0;
745 bool first = true;
746 int r;
747
748 assert(p);
749 assert(_ret);
750
751 saved_rindex = p->rindex;
752
753 for (;;) {
754 uint8_t c, d;
755
756 r = dns_packet_read_uint8(p, &c, NULL);
757 if (r < 0)
758 goto fail;
759
760 if (c == 0)
761 /* End of name */
762 break;
763 else if (c <= 63) {
764 _cleanup_free_ char *t = NULL;
765 const char *label;
766
767 /* Literal label */
768 r = dns_packet_read(p, c, (const void**) &label, NULL);
769 if (r < 0)
770 goto fail;
771
772 r = dns_label_escape(label, c, &t);
773 if (r < 0)
774 goto fail;
775
776 if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
777 r = -ENOMEM;
778 goto fail;
779 }
780
781 if (!first)
782 ret[n++] = '.';
783 else
784 first = false;
785
786 memcpy(ret + n, t, c);
787 n += r;
788 continue;
789 } else if ((c & 0xc0) == 0xc0) {
790 uint16_t ptr;
791
792 /* Pointer */
793 r = dns_packet_read_uint8(p, &d, NULL);
794 if (r < 0)
795 goto fail;
796
797 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
798 if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) {
799 r = -EBADMSG;
800 goto fail;
801 }
802
803 if (after_rindex == 0)
804 after_rindex = p->rindex;
805
806 p->rindex = ptr;
807 } else
808 goto fail;
809 }
810
811 if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
812 r = -ENOMEM;
813 goto fail;
814 }
815
816 ret[n] = 0;
817
818 if (after_rindex != 0)
819 p->rindex= after_rindex;
820
821 *_ret = ret;
822 ret = NULL;
823
824 if (start)
825 *start = saved_rindex;
826
827 return 0;
828
829fail:
830 dns_packet_rewind(p, saved_rindex);
831 return r;
832}
833
faa133f3
LP
834int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
835 _cleanup_free_ char *name = NULL;
836 uint16_t class, type;
837 DnsResourceKey *key;
74b2466e
LP
838 size_t saved_rindex;
839 int r;
840
841 assert(p);
842 assert(ret);
843
844 saved_rindex = p->rindex;
845
faa133f3 846 r = dns_packet_read_name(p, &name, NULL);
74b2466e
LP
847 if (r < 0)
848 goto fail;
849
faa133f3 850 r = dns_packet_read_uint16(p, &type, NULL);
74b2466e
LP
851 if (r < 0)
852 goto fail;
853
faa133f3 854 r = dns_packet_read_uint16(p, &class, NULL);
74b2466e
LP
855 if (r < 0)
856 goto fail;
857
faa133f3
LP
858 key = dns_resource_key_new_consume(class, type, name);
859 if (!key) {
860 r = -ENOMEM;
861 goto fail;
862 }
863
864 name = NULL;
865 *ret = key;
74b2466e
LP
866
867 if (start)
868 *start = saved_rindex;
869
870 return 0;
871fail:
872 dns_packet_rewind(p, saved_rindex);
873 return r;
874}
875
876int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
faa133f3
LP
877 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
878 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
74b2466e
LP
879 size_t saved_rindex, offset;
880 uint16_t rdlength;
881 const void *d;
882 int r;
883
884 assert(p);
885 assert(ret);
886
4e0296a9 887 saved_rindex = p->rindex;
74b2466e 888
faa133f3 889 r = dns_packet_read_key(p, &key, NULL);
74b2466e
LP
890 if (r < 0)
891 goto fail;
892
0e2bcd6a
LP
893 if (key->class == DNS_CLASS_ANY ||
894 key->type == DNS_TYPE_ANY) {
895 r = -EBADMSG;
896 goto fail;
897 }
898
faa133f3
LP
899 rr = dns_resource_record_new(key);
900 if (!rr) {
901 r = -ENOMEM;
902 goto fail;
903 }
904
74b2466e
LP
905 r = dns_packet_read_uint32(p, &rr->ttl, NULL);
906 if (r < 0)
907 goto fail;
908
909 r = dns_packet_read_uint16(p, &rdlength, NULL);
910 if (r < 0)
911 goto fail;
912
913 if (p->rindex + rdlength > p->size) {
914 r = -EBADMSG;
915 goto fail;
916 }
917
918 offset = p->rindex;
919
faa133f3 920 switch (rr->key->type) {
74b2466e
LP
921
922 case DNS_TYPE_PTR:
923 case DNS_TYPE_NS:
924 case DNS_TYPE_CNAME:
925 r = dns_packet_read_name(p, &rr->ptr.name, NULL);
926 break;
927
928 case DNS_TYPE_HINFO:
929 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
930 if (r < 0)
931 goto fail;
932
933 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
934 break;
935
2e276efc
ZJS
936 case DNS_TYPE_TXT: {
937 char *s;
938
939 while (p->rindex < p->size) {
940 r = dns_packet_read_string(p, &s, NULL);
941 if (r < 0)
942 goto fail;
943
944 r = strv_consume(&rr->txt.strings, s);
945 if (r < 0)
946 goto fail;
947 };
948 break;
949 }
950
74b2466e 951 case DNS_TYPE_A:
623a4c97 952 r = dns_packet_read_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
74b2466e
LP
953 break;
954
955 case DNS_TYPE_AAAA:
623a4c97 956 r = dns_packet_read_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
74b2466e
LP
957 break;
958
7e8e0422
LP
959 case DNS_TYPE_SOA:
960 r = dns_packet_read_name(p, &rr->soa.mname, NULL);
961 if (r < 0)
962 goto fail;
963
964 r = dns_packet_read_name(p, &rr->soa.rname, NULL);
965 if (r < 0)
966 goto fail;
967
968 r = dns_packet_read_uint32(p, &rr->soa.serial, NULL);
969 if (r < 0)
970 goto fail;
971
972 r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL);
973 if (r < 0)
974 goto fail;
975
976 r = dns_packet_read_uint32(p, &rr->soa.retry, NULL);
977 if (r < 0)
978 goto fail;
979
980 r = dns_packet_read_uint32(p, &rr->soa.expire, NULL);
981 if (r < 0)
982 goto fail;
983
984 r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL);
985 break;
986
623a4c97 987 case DNS_TYPE_MX:
946c7094
ZJS
988 r = dns_packet_read_uint16(p, &rr->mx.priority, NULL);
989 if (r < 0)
990 goto fail;
991
992 r = dns_packet_read_name(p, &rr->mx.exchange, NULL);
993 break;
994
623a4c97
LP
995 case DNS_TYPE_SRV:
996 case DNS_TYPE_DNAME:
997 case DNS_TYPE_SSHFP:
74b2466e
LP
998 default:
999 r = dns_packet_read(p, rdlength, &d, NULL);
1000 if (r < 0)
1001 goto fail;
1002
1003 rr->generic.data = memdup(d, rdlength);
1004 if (!rr->generic.data) {
1005 r = -ENOMEM;
1006 goto fail;
1007 }
1008
1009 rr->generic.size = rdlength;
1010 break;
1011 }
1012 if (r < 0)
1013 goto fail;
1014 if (p->rindex != offset + rdlength) {
1015 r = -EBADMSG;
1016 goto fail;
1017 }
1018
1019 *ret = rr;
1020 rr = NULL;
1021
1022 if (start)
1023 *start = saved_rindex;
1024
1025 return 0;
1026fail:
1027 dns_packet_rewind(p, saved_rindex);
1028 return r;
1029}
1030
faa133f3
LP
1031int dns_packet_extract(DnsPacket *p) {
1032 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
1033 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
1034 size_t saved_rindex;
1035 unsigned n, i;
74b2466e
LP
1036 int r;
1037
faa133f3 1038 saved_rindex = p->rindex;
322345fd
LP
1039 dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
1040
3cb10d3a 1041 n = DNS_PACKET_QDCOUNT(p);
faa133f3
LP
1042 if (n > 0) {
1043 question = dns_question_new(n);
1044 if (!question) {
1045 r = -ENOMEM;
1046 goto finish;
1047 }
74b2466e 1048
faa133f3
LP
1049 for (i = 0; i < n; i++) {
1050 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
74b2466e 1051
faa133f3
LP
1052 r = dns_packet_read_key(p, &key, NULL);
1053 if (r < 0)
1054 goto finish;
74b2466e 1055
faa133f3
LP
1056 r = dns_question_add(question, key);
1057 if (r < 0)
1058 goto finish;
1059 }
1060 }
322345fd 1061
faa133f3
LP
1062 n = DNS_PACKET_RRCOUNT(p);
1063 if (n > 0) {
1064 answer = dns_answer_new(n);
1065 if (!answer) {
1066 r = -ENOMEM;
1067 goto finish;
1068 }
322345fd 1069
faa133f3
LP
1070 for (i = 0; i < n; i++) {
1071 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
322345fd 1072
faa133f3
LP
1073 r = dns_packet_read_rr(p, &rr, NULL);
1074 if (r < 0)
1075 goto finish;
322345fd 1076
faa133f3
LP
1077 r = dns_answer_add(answer, rr);
1078 if (r < 0)
1079 goto finish;
1080 }
322345fd
LP
1081 }
1082
faa133f3
LP
1083 p->question = question;
1084 question = NULL;
322345fd 1085
faa133f3
LP
1086 p->answer = answer;
1087 answer = NULL;
322345fd 1088
faa133f3 1089 r = 0;
322345fd
LP
1090
1091finish:
1092 p->rindex = saved_rindex;
1093 return r;
1094}
1095
74b2466e
LP
1096static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
1097 [DNS_RCODE_SUCCESS] = "SUCCESS",
1098 [DNS_RCODE_FORMERR] = "FORMERR",
1099 [DNS_RCODE_SERVFAIL] = "SERVFAIL",
1100 [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
1101 [DNS_RCODE_NOTIMP] = "NOTIMP",
1102 [DNS_RCODE_REFUSED] = "REFUSED",
1103 [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
1104 [DNS_RCODE_YXRRSET] = "YRRSET",
1105 [DNS_RCODE_NXRRSET] = "NXRRSET",
1106 [DNS_RCODE_NOTAUTH] = "NOTAUTH",
1107 [DNS_RCODE_NOTZONE] = "NOTZONE",
1108 [DNS_RCODE_BADVERS] = "BADVERS",
1109 [DNS_RCODE_BADKEY] = "BADKEY",
1110 [DNS_RCODE_BADTIME] = "BADTIME",
1111 [DNS_RCODE_BADMODE] = "BADMODE",
1112 [DNS_RCODE_BADNAME] = "BADNAME",
1113 [DNS_RCODE_BADALG] = "BADALG",
1114 [DNS_RCODE_BADTRUNC] = "BADTRUNC",
1115};
1116DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);
1716f6dc
LP
1117
1118static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
1119 [DNS_PROTOCOL_DNS] = "dns",
1120 [DNS_PROTOCOL_MDNS] = "mdns",
1121 [DNS_PROTOCOL_LLMNR] = "llmnr",
1122};
1123DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);