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