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