chiark / gitweb /
5eaee2cb4f751e2be52a1475deb869366f3d6ad1
[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_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
100 DnsPacket *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
110 static 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
126 DnsPacket *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
140 int 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
152 int 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
175 int 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
209 static 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
252 static 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
274 int 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
288 int 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
303 int 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
319 int 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
337 int 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
359 int 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
379 int 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
435 done:
436         if (start)
437                 *start = saved_size;
438
439         return 0;
440
441 fail:
442         dns_packet_truncate(p, saved_size);
443         return r;
444 }
445
446 int 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
472 fail:
473         dns_packet_truncate(p, saved_size);
474         return r;
475 }
476
477 int 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         case DNS_TYPE_TXT:
553         case DNS_TYPE_SRV:
554         case DNS_TYPE_DNAME:
555         case DNS_TYPE_SSHFP:
556         default:
557                 r = dns_packet_append_blob(p, rr->generic.data, rr->generic.size, NULL);
558                 break;
559         }
560         if (r < 0)
561                 goto fail;
562
563         /* Let's calculate the actual data size and update the field */
564         rdlength = p->size - rdlength_offset - sizeof(uint16_t);
565         if (rdlength > 0xFFFF) {
566                 r = ENOSPC;
567                 goto fail;
568         }
569
570         end = p->size;
571         p->size = rdlength_offset;
572         r = dns_packet_append_uint16(p, rdlength, NULL);
573         if (r < 0)
574                 goto fail;
575         p->size = end;
576
577         return 0;
578
579 fail:
580         dns_packet_truncate(p, saved_size);
581         return r;
582 }
583
584
585 int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
586         assert(p);
587
588         if (p->rindex + sz > p->size)
589                 return -EMSGSIZE;
590
591         if (ret)
592                 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
593
594         if (start)
595                 *start = p->rindex;
596
597         p->rindex += sz;
598         return 0;
599 }
600
601 void dns_packet_rewind(DnsPacket *p, size_t idx) {
602         assert(p);
603         assert(idx <= p->size);
604         assert(idx >= DNS_PACKET_HEADER_SIZE);
605
606         p->rindex = idx;
607 }
608
609 int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start) {
610         const void *q;
611         int r;
612
613         assert(p);
614         assert(d);
615
616         r = dns_packet_read(p, sz, &q, start);
617         if (r < 0)
618                 return r;
619
620         memcpy(d, q, sz);
621         return 0;
622 }
623
624 int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
625         const void *d;
626         int r;
627
628         assert(p);
629
630         r = dns_packet_read(p, sizeof(uint8_t), &d, start);
631         if (r < 0)
632                 return r;
633
634         *ret = ((uint8_t*) d)[0];
635         return 0;
636 }
637
638 int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
639         const void *d;
640         int r;
641
642         assert(p);
643
644         r = dns_packet_read(p, sizeof(uint16_t), &d, start);
645         if (r < 0)
646                 return r;
647
648         *ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) |
649                 ((uint16_t) ((uint8_t*) d)[1]);
650         return 0;
651 }
652
653 int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
654         const void *d;
655         int r;
656
657         assert(p);
658
659         r = dns_packet_read(p, sizeof(uint32_t), &d, start);
660         if (r < 0)
661                 return r;
662
663         *ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) |
664                (((uint32_t) ((uint8_t*) d)[1]) << 16) |
665                (((uint32_t) ((uint8_t*) d)[2]) << 8) |
666                 ((uint32_t) ((uint8_t*) d)[3]);
667
668         return 0;
669 }
670
671 int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
672         size_t saved_rindex;
673         const void *d;
674         char *t;
675         uint8_t c;
676         int r;
677
678         assert(p);
679
680         saved_rindex = p->rindex;
681
682         r = dns_packet_read_uint8(p, &c, NULL);
683         if (r < 0)
684                 goto fail;
685
686         r = dns_packet_read(p, c, &d, NULL);
687         if (r < 0)
688                 goto fail;
689
690         if (memchr(d, 0, c)) {
691                 r = -EBADMSG;
692                 goto fail;
693         }
694
695         t = strndup(d, c);
696         if (!t) {
697                 r = -ENOMEM;
698                 goto fail;
699         }
700
701         if (!utf8_is_valid(t)) {
702                 free(t);
703                 r = -EBADMSG;
704                 goto fail;
705         }
706
707         *ret = t;
708
709         if (start)
710                 *start = saved_rindex;
711
712         return 0;
713
714 fail:
715         dns_packet_rewind(p, saved_rindex);
716         return r;
717 }
718
719 int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
720         size_t saved_rindex, after_rindex = 0;
721         _cleanup_free_ char *ret = NULL;
722         size_t n = 0, allocated = 0;
723         bool first = true;
724         int r;
725
726         assert(p);
727         assert(_ret);
728
729         saved_rindex = p->rindex;
730
731         for (;;) {
732                 uint8_t c, d;
733
734                 r = dns_packet_read_uint8(p, &c, NULL);
735                 if (r < 0)
736                         goto fail;
737
738                 if (c == 0)
739                         /* End of name */
740                         break;
741                 else if (c <= 63) {
742                         _cleanup_free_ char *t = NULL;
743                         const char *label;
744
745                         /* Literal label */
746                         r = dns_packet_read(p, c, (const void**) &label, NULL);
747                         if (r < 0)
748                                 goto fail;
749
750                         r = dns_label_escape(label, c, &t);
751                         if (r < 0)
752                                 goto fail;
753
754                         if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
755                                 r = -ENOMEM;
756                                 goto fail;
757                         }
758
759                         if (!first)
760                                 ret[n++] = '.';
761                         else
762                                 first = false;
763
764                         memcpy(ret + n, t, c);
765                         n += r;
766                         continue;
767                 } else if ((c & 0xc0) == 0xc0) {
768                         uint16_t ptr;
769
770                         /* Pointer */
771                         r = dns_packet_read_uint8(p, &d, NULL);
772                         if (r < 0)
773                                 goto fail;
774
775                         ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
776                         if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) {
777                                 r = -EBADMSG;
778                                 goto fail;
779                         }
780
781                         if (after_rindex == 0)
782                                 after_rindex = p->rindex;
783
784                         p->rindex = ptr;
785                 } else
786                         goto fail;
787         }
788
789         if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
790                 r = -ENOMEM;
791                 goto fail;
792         }
793
794         ret[n] = 0;
795
796         if (after_rindex != 0)
797                 p->rindex= after_rindex;
798
799         *_ret = ret;
800         ret = NULL;
801
802         if (start)
803                 *start = saved_rindex;
804
805         return 0;
806
807 fail:
808         dns_packet_rewind(p, saved_rindex);
809         return r;
810 }
811
812 int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
813         _cleanup_free_ char *name = NULL;
814         uint16_t class, type;
815         DnsResourceKey *key;
816         size_t saved_rindex;
817         int r;
818
819         assert(p);
820         assert(ret);
821
822         saved_rindex = p->rindex;
823
824         r = dns_packet_read_name(p, &name, NULL);
825         if (r < 0)
826                 goto fail;
827
828         r = dns_packet_read_uint16(p, &type, NULL);
829         if (r < 0)
830                 goto fail;
831
832         r = dns_packet_read_uint16(p, &class, NULL);
833         if (r < 0)
834                 goto fail;
835
836         key = dns_resource_key_new_consume(class, type, name);
837         if (!key) {
838                 r = -ENOMEM;
839                 goto fail;
840         }
841
842         name = NULL;
843         *ret = key;
844
845         if (start)
846                 *start = saved_rindex;
847
848         return 0;
849 fail:
850         dns_packet_rewind(p, saved_rindex);
851         return r;
852 }
853
854 int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
855         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
856         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
857         size_t saved_rindex, offset;
858         uint16_t rdlength;
859         const void *d;
860         int r;
861
862         assert(p);
863         assert(ret);
864
865         saved_rindex = p->rindex;
866
867         r = dns_packet_read_key(p, &key, NULL);
868         if (r < 0)
869                 goto fail;
870
871         rr = dns_resource_record_new(key);
872         if (!rr) {
873                 r = -ENOMEM;
874                 goto fail;
875         }
876
877         r = dns_packet_read_uint32(p, &rr->ttl, NULL);
878         if (r < 0)
879                 goto fail;
880
881         r = dns_packet_read_uint16(p, &rdlength, NULL);
882         if (r < 0)
883                 goto fail;
884
885         if (p->rindex + rdlength > p->size) {
886                 r = -EBADMSG;
887                 goto fail;
888         }
889
890         offset = p->rindex;
891
892         switch (rr->key->type) {
893
894         case DNS_TYPE_PTR:
895         case DNS_TYPE_NS:
896         case DNS_TYPE_CNAME:
897                 r = dns_packet_read_name(p, &rr->ptr.name, NULL);
898                 break;
899
900         case DNS_TYPE_HINFO:
901                 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
902                 if (r < 0)
903                         goto fail;
904
905                 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
906                 break;
907
908         case DNS_TYPE_A:
909                 r = dns_packet_read_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
910                 break;
911
912         case DNS_TYPE_AAAA:
913                 r = dns_packet_read_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
914                 break;
915
916         case DNS_TYPE_SOA:
917                 r = dns_packet_read_name(p, &rr->soa.mname, NULL);
918                 if (r < 0)
919                         goto fail;
920
921                 r = dns_packet_read_name(p, &rr->soa.rname, NULL);
922                 if (r < 0)
923                         goto fail;
924
925                 r = dns_packet_read_uint32(p, &rr->soa.serial, NULL);
926                 if (r < 0)
927                         goto fail;
928
929                 r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL);
930                 if (r < 0)
931                         goto fail;
932
933                 r = dns_packet_read_uint32(p, &rr->soa.retry, NULL);
934                 if (r < 0)
935                         goto fail;
936
937                 r = dns_packet_read_uint32(p, &rr->soa.expire, NULL);
938                 if (r < 0)
939                         goto fail;
940
941                 r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL);
942                 break;
943
944         case DNS_TYPE_MX:
945         case DNS_TYPE_TXT:
946         case DNS_TYPE_SRV:
947         case DNS_TYPE_DNAME:
948         case DNS_TYPE_SSHFP:
949         default:
950                 r = dns_packet_read(p, rdlength, &d, NULL);
951                 if (r < 0)
952                         goto fail;
953
954                 rr->generic.data = memdup(d, rdlength);
955                 if (!rr->generic.data) {
956                         r = -ENOMEM;
957                         goto fail;
958                 }
959
960                 rr->generic.size = rdlength;
961                 break;
962         }
963         if (r < 0)
964                 goto fail;
965         if (p->rindex != offset + rdlength) {
966                 r = -EBADMSG;
967                 goto fail;
968         }
969
970         *ret = rr;
971         rr = NULL;
972
973         if (start)
974                 *start = saved_rindex;
975
976         return 0;
977 fail:
978         dns_packet_rewind(p, saved_rindex);
979         return r;
980 }
981
982 int dns_packet_extract(DnsPacket *p) {
983         _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
984         _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
985         size_t saved_rindex;
986         unsigned n, i;
987         int r;
988
989         saved_rindex = p->rindex;
990         dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
991
992         n = DNS_PACKET_QDCOUNT(p);
993         if (n > 0) {
994                 question = dns_question_new(n);
995                 if (!question) {
996                         r = -ENOMEM;
997                         goto finish;
998                 }
999
1000                 for (i = 0; i < n; i++) {
1001                         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
1002
1003                         r = dns_packet_read_key(p, &key, NULL);
1004                         if (r < 0)
1005                                 goto finish;
1006
1007                         r = dns_question_add(question, key);
1008                         if (r < 0)
1009                                 goto finish;
1010                 }
1011         }
1012
1013         n = DNS_PACKET_RRCOUNT(p);
1014         if (n > 0) {
1015                 answer = dns_answer_new(n);
1016                 if (!answer) {
1017                         r = -ENOMEM;
1018                         goto finish;
1019                 }
1020
1021                 for (i = 0; i < n; i++) {
1022                         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
1023
1024                         r = dns_packet_read_rr(p, &rr, NULL);
1025                         if (r < 0)
1026                                 goto finish;
1027
1028                         r = dns_answer_add(answer, rr);
1029                         if (r < 0)
1030                                 goto finish;
1031                 }
1032         }
1033
1034         p->question = question;
1035         question = NULL;
1036
1037         p->answer = answer;
1038         answer = NULL;
1039
1040         r = 0;
1041
1042 finish:
1043         p->rindex = saved_rindex;
1044         return r;
1045 }
1046
1047 static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
1048         [DNS_RCODE_SUCCESS] = "SUCCESS",
1049         [DNS_RCODE_FORMERR] = "FORMERR",
1050         [DNS_RCODE_SERVFAIL] = "SERVFAIL",
1051         [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
1052         [DNS_RCODE_NOTIMP] = "NOTIMP",
1053         [DNS_RCODE_REFUSED] = "REFUSED",
1054         [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
1055         [DNS_RCODE_YXRRSET] = "YRRSET",
1056         [DNS_RCODE_NXRRSET] = "NXRRSET",
1057         [DNS_RCODE_NOTAUTH] = "NOTAUTH",
1058         [DNS_RCODE_NOTZONE] = "NOTZONE",
1059         [DNS_RCODE_BADVERS] = "BADVERS",
1060         [DNS_RCODE_BADKEY] = "BADKEY",
1061         [DNS_RCODE_BADTIME] = "BADTIME",
1062         [DNS_RCODE_BADMODE] = "BADMODE",
1063         [DNS_RCODE_BADNAME] = "BADNAME",
1064         [DNS_RCODE_BADALG] = "BADALG",
1065         [DNS_RCODE_BADTRUNC] = "BADTRUNC",
1066 };
1067 DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);
1068
1069 static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
1070         [DNS_PROTOCOL_DNS] = "dns",
1071         [DNS_PROTOCOL_MDNS] = "mdns",
1072         [DNS_PROTOCOL_LLMNR] = "llmnr",
1073 };
1074 DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);