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