chiark / gitweb /
resolve-host: use the usual log message when encountering a dbus parse failure
[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         if (key->class == DNS_CLASS_ANY ||
872             key->type == DNS_TYPE_ANY) {
873                 r = -EBADMSG;
874                 goto fail;
875         }
876
877         rr = dns_resource_record_new(key);
878         if (!rr) {
879                 r = -ENOMEM;
880                 goto fail;
881         }
882
883         r = dns_packet_read_uint32(p, &rr->ttl, NULL);
884         if (r < 0)
885                 goto fail;
886
887         r = dns_packet_read_uint16(p, &rdlength, NULL);
888         if (r < 0)
889                 goto fail;
890
891         if (p->rindex + rdlength > p->size) {
892                 r = -EBADMSG;
893                 goto fail;
894         }
895
896         offset = p->rindex;
897
898         switch (rr->key->type) {
899
900         case DNS_TYPE_PTR:
901         case DNS_TYPE_NS:
902         case DNS_TYPE_CNAME:
903                 r = dns_packet_read_name(p, &rr->ptr.name, NULL);
904                 break;
905
906         case DNS_TYPE_HINFO:
907                 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
908                 if (r < 0)
909                         goto fail;
910
911                 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
912                 break;
913
914         case DNS_TYPE_A:
915                 r = dns_packet_read_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
916                 break;
917
918         case DNS_TYPE_AAAA:
919                 r = dns_packet_read_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
920                 break;
921
922         case DNS_TYPE_SOA:
923                 r = dns_packet_read_name(p, &rr->soa.mname, NULL);
924                 if (r < 0)
925                         goto fail;
926
927                 r = dns_packet_read_name(p, &rr->soa.rname, NULL);
928                 if (r < 0)
929                         goto fail;
930
931                 r = dns_packet_read_uint32(p, &rr->soa.serial, NULL);
932                 if (r < 0)
933                         goto fail;
934
935                 r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL);
936                 if (r < 0)
937                         goto fail;
938
939                 r = dns_packet_read_uint32(p, &rr->soa.retry, NULL);
940                 if (r < 0)
941                         goto fail;
942
943                 r = dns_packet_read_uint32(p, &rr->soa.expire, NULL);
944                 if (r < 0)
945                         goto fail;
946
947                 r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL);
948                 break;
949
950         case DNS_TYPE_MX:
951         case DNS_TYPE_TXT:
952         case DNS_TYPE_SRV:
953         case DNS_TYPE_DNAME:
954         case DNS_TYPE_SSHFP:
955         default:
956                 r = dns_packet_read(p, rdlength, &d, NULL);
957                 if (r < 0)
958                         goto fail;
959
960                 rr->generic.data = memdup(d, rdlength);
961                 if (!rr->generic.data) {
962                         r = -ENOMEM;
963                         goto fail;
964                 }
965
966                 rr->generic.size = rdlength;
967                 break;
968         }
969         if (r < 0)
970                 goto fail;
971         if (p->rindex != offset + rdlength) {
972                 r = -EBADMSG;
973                 goto fail;
974         }
975
976         *ret = rr;
977         rr = NULL;
978
979         if (start)
980                 *start = saved_rindex;
981
982         return 0;
983 fail:
984         dns_packet_rewind(p, saved_rindex);
985         return r;
986 }
987
988 int dns_packet_extract(DnsPacket *p) {
989         _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
990         _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
991         size_t saved_rindex;
992         unsigned n, i;
993         int r;
994
995         saved_rindex = p->rindex;
996         dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
997
998         n = DNS_PACKET_QDCOUNT(p);
999         if (n > 0) {
1000                 question = dns_question_new(n);
1001                 if (!question) {
1002                         r = -ENOMEM;
1003                         goto finish;
1004                 }
1005
1006                 for (i = 0; i < n; i++) {
1007                         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
1008
1009                         r = dns_packet_read_key(p, &key, NULL);
1010                         if (r < 0)
1011                                 goto finish;
1012
1013                         r = dns_question_add(question, key);
1014                         if (r < 0)
1015                                 goto finish;
1016                 }
1017         }
1018
1019         n = DNS_PACKET_RRCOUNT(p);
1020         if (n > 0) {
1021                 answer = dns_answer_new(n);
1022                 if (!answer) {
1023                         r = -ENOMEM;
1024                         goto finish;
1025                 }
1026
1027                 for (i = 0; i < n; i++) {
1028                         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
1029
1030                         r = dns_packet_read_rr(p, &rr, NULL);
1031                         if (r < 0)
1032                                 goto finish;
1033
1034                         r = dns_answer_add(answer, rr);
1035                         if (r < 0)
1036                                 goto finish;
1037                 }
1038         }
1039
1040         p->question = question;
1041         question = NULL;
1042
1043         p->answer = answer;
1044         answer = NULL;
1045
1046         r = 0;
1047
1048 finish:
1049         p->rindex = saved_rindex;
1050         return r;
1051 }
1052
1053 static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
1054         [DNS_RCODE_SUCCESS] = "SUCCESS",
1055         [DNS_RCODE_FORMERR] = "FORMERR",
1056         [DNS_RCODE_SERVFAIL] = "SERVFAIL",
1057         [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
1058         [DNS_RCODE_NOTIMP] = "NOTIMP",
1059         [DNS_RCODE_REFUSED] = "REFUSED",
1060         [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
1061         [DNS_RCODE_YXRRSET] = "YRRSET",
1062         [DNS_RCODE_NXRRSET] = "NXRRSET",
1063         [DNS_RCODE_NOTAUTH] = "NOTAUTH",
1064         [DNS_RCODE_NOTZONE] = "NOTZONE",
1065         [DNS_RCODE_BADVERS] = "BADVERS",
1066         [DNS_RCODE_BADKEY] = "BADKEY",
1067         [DNS_RCODE_BADTIME] = "BADTIME",
1068         [DNS_RCODE_BADMODE] = "BADMODE",
1069         [DNS_RCODE_BADNAME] = "BADNAME",
1070         [DNS_RCODE_BADALG] = "BADALG",
1071         [DNS_RCODE_BADTRUNC] = "BADTRUNC",
1072 };
1073 DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);
1074
1075 static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
1076         [DNS_PROTOCOL_DNS] = "dns",
1077         [DNS_PROTOCOL_MDNS] = "mdns",
1078         [DNS_PROTOCOL_LLMNR] = "llmnr",
1079 };
1080 DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);