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