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