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