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