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