chiark / gitweb /
change type for address family to "int"
[elogind.git] / src / resolve / resolved-dns-packet.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20  ***/
21
22 #include "utf8.h"
23 #include "util.h"
24 #include "resolved-dns-domain.h"
25 #include "resolved-dns-packet.h"
26
27 int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
28         DnsPacket *p;
29         size_t a;
30
31         assert(ret);
32
33         if (mtu <= 0)
34                 a = DNS_PACKET_SIZE_START;
35         else
36                 a = mtu;
37
38         if (a < DNS_PACKET_HEADER_SIZE)
39                 a = DNS_PACKET_HEADER_SIZE;
40
41         /* round up to next page size */
42         a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket));
43
44         /* make sure we never allocate more than useful */
45         if (a > DNS_PACKET_SIZE_MAX)
46                 a = DNS_PACKET_SIZE_MAX;
47
48         p = malloc0(ALIGN(sizeof(DnsPacket)) + a);
49         if (!p)
50                 return -ENOMEM;
51
52         p->size = p->rindex = DNS_PACKET_HEADER_SIZE;
53         p->allocated = a;
54         p->protocol = protocol;
55         p->n_ref = 1;
56
57         *ret = p;
58
59         return 0;
60 }
61
62 int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
63         DnsPacket *p;
64         DnsPacketHeader *h;
65         int r;
66
67         assert(ret);
68
69         r = dns_packet_new(&p, protocol, mtu);
70         if (r < 0)
71                 return r;
72
73         h = DNS_PACKET_HEADER(p);
74
75         if (protocol == DNS_PROTOCOL_DNS)
76                 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, 0)); /* ask for recursion */
77         else
78                 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0));
79
80         *ret = p;
81         return 0;
82 }
83
84 DnsPacket *dns_packet_ref(DnsPacket *p) {
85
86         if (!p)
87                 return NULL;
88
89         assert(p->n_ref > 0);
90         p->n_ref++;
91         return p;
92 }
93
94 static void dns_packet_free(DnsPacket *p) {
95         char *s;
96
97         assert(p);
98
99         if (p->rrs)
100                 dns_resource_record_freev(p->rrs, DNS_PACKET_RRCOUNT(p));
101
102         while ((s = hashmap_steal_first_key(p->names)))
103                 free(s);
104         hashmap_free(p->names);
105
106         free(p->data);
107         free(p);
108 }
109
110 DnsPacket *dns_packet_unref(DnsPacket *p) {
111         if (!p)
112                 return NULL;
113
114         assert(p->n_ref > 0);
115
116         if (p->n_ref == 1)
117                 dns_packet_free(p);
118         else
119                 p->n_ref--;
120
121         return NULL;
122 }
123
124 int dns_packet_validate(DnsPacket *p) {
125         assert(p);
126
127         if (p->size < DNS_PACKET_HEADER_SIZE)
128                 return -EBADMSG;
129
130         if (p->size > DNS_PACKET_SIZE_MAX)
131                 return -EBADMSG;
132
133         return 0;
134 }
135
136 int dns_packet_validate_reply(DnsPacket *p) {
137         int r;
138
139         assert(p);
140
141         r = dns_packet_validate(p);
142         if (r < 0)
143                 return r;
144
145         if (DNS_PACKET_QR(p) == 0)
146                 return -EBADMSG;
147
148         if (DNS_PACKET_OPCODE(p) != 0)
149                 return -EBADMSG;
150
151         return 0;
152 }
153
154 static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
155         assert(p);
156
157         if (p->size + add > p->allocated) {
158                 size_t a;
159
160                 a = PAGE_ALIGN((p->size + add) * 2);
161                 if (a > DNS_PACKET_SIZE_MAX)
162                         a = DNS_PACKET_SIZE_MAX;
163
164                 if (p->size + add > a)
165                         return -EMSGSIZE;
166
167                 if (p->data) {
168                         void *d;
169
170                         d = realloc(p->data, a);
171                         if (!d)
172                                 return -ENOMEM;
173
174                         p->data = d;
175                 } else {
176                         p->data = malloc(a);
177                         if (!p->data)
178                                 return -ENOMEM;
179
180                         memcpy(p->data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size);
181                         memzero((uint8_t*) p->data + p->size, a - p->size);
182                 }
183
184                 p->allocated = a;
185         }
186
187         if (start)
188                 *start = p->size;
189
190         if (ret)
191                 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size;
192
193         p->size += add;
194         return 0;
195 }
196
197 static void dns_packet_truncate(DnsPacket *p, size_t sz) {
198         Iterator i;
199         char *s;
200         void *n;
201
202         assert(p);
203
204         if (p->size <= sz)
205                 return;
206
207         HASHMAP_FOREACH_KEY(s, n, p->names, i) {
208
209                 if (PTR_TO_SIZE(n) < sz)
210                         continue;
211
212                 hashmap_remove(p->names, s);
213                 free(s);
214         }
215
216         p->size = sz;
217 }
218
219 int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) {
220         void *d;
221         int r;
222
223         assert(p);
224
225         r = dns_packet_extend(p, sizeof(uint8_t), &d, start);
226         if (r < 0)
227                 return r;
228
229         ((uint8_t*) d)[0] = v;
230
231         return 0;
232 }
233
234 int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
235         void *d;
236         int r;
237
238         assert(p);
239
240         r = dns_packet_extend(p, sizeof(uint16_t), &d, start);
241         if (r < 0)
242                 return r;
243
244         ((uint8_t*) d)[0] = (uint8_t) (v >> 8);
245         ((uint8_t*) d)[1] = (uint8_t) (v & 255);
246
247         return 0;
248 }
249
250 int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
251         void *d;
252         size_t l;
253         int r;
254
255         assert(p);
256         assert(s);
257
258         l = strlen(s);
259         if (l > 255)
260                 return -E2BIG;
261
262         r = dns_packet_extend(p, 1 + l, &d, start);
263         if (r < 0)
264                 return r;
265
266         ((uint8_t*) d)[0] = (uint8_t) l;
267         memcpy(((uint8_t*) d) + 1, s, l);
268
269         return 0;
270 }
271
272 int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
273         void *w;
274         int r;
275
276         assert(p);
277         assert(d);
278
279         if (l > DNS_LABEL_MAX)
280                 return -E2BIG;
281
282         r = dns_packet_extend(p, 1 + l, &w, start);
283         if (r < 0)
284                 return r;
285
286         ((uint8_t*) w)[0] = (uint8_t) l;
287         memcpy(((uint8_t*) w) + 1, d, l);
288
289         return 0;
290 }
291
292 int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
293         size_t saved_size;
294         int r;
295
296         assert(p);
297         assert(name);
298
299         saved_size = p->size;
300
301         while (*name) {
302                 _cleanup_free_ char *s = NULL;
303                 char label[DNS_LABEL_MAX];
304                 size_t n;
305
306                 n = PTR_TO_SIZE(hashmap_get(p->names, name));
307                 if (n > 0) {
308                         assert(n < p->size);
309
310                         if (n < 0x4000) {
311                                 r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
312                                 if (r < 0)
313                                         goto fail;
314
315                                 goto done;
316                         }
317                 }
318
319                 s = strdup(name);
320                 if (!s) {
321                         r = -ENOMEM;
322                         goto fail;
323                 }
324
325                 r = dns_label_unescape(&name, label, sizeof(label));
326                 if (r < 0)
327                         goto fail;
328
329                 r = dns_packet_append_label(p, label, r, &n);
330                 if (r < 0)
331                         goto fail;
332
333                 r = hashmap_ensure_allocated(&p->names, dns_name_hash_func, dns_name_compare_func);
334                 if (r < 0)
335                         goto fail;
336
337                 r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
338                 if (r < 0)
339                         goto fail;
340
341                 s = NULL;
342         }
343
344         r = dns_packet_append_uint8(p, 0, NULL);
345         if (r < 0)
346                 return r;
347
348 done:
349         if (start)
350                 *start = saved_size;
351
352         return 0;
353
354 fail:
355         dns_packet_truncate(p, saved_size);
356         return r;
357 }
358
359 int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
360         size_t saved_size;
361         int r;
362
363         assert(p);
364         assert(k);
365
366         saved_size = p->size;
367
368         r = dns_packet_append_name(p, k->name, NULL);
369         if (r < 0)
370                 goto fail;
371
372         r = dns_packet_append_uint16(p, k->type, NULL);
373         if (r < 0)
374                 goto fail;
375
376         r = dns_packet_append_uint16(p, k->class, NULL);
377         if (r < 0)
378                 goto fail;
379
380         if (start)
381                 *start = saved_size;
382
383         return 0;
384
385 fail:
386         dns_packet_truncate(p, saved_size);
387         return r;
388 }
389
390 int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
391         assert(p);
392
393         if (p->rindex + sz > p->size)
394                 return -EMSGSIZE;
395
396         if (ret)
397                 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
398
399         if (start)
400                 *start = p->rindex;
401
402         p->rindex += sz;
403         return 0;
404 }
405
406 void dns_packet_rewind(DnsPacket *p, size_t idx) {
407         assert(p);
408         assert(idx <= p->size);
409         assert(idx >= DNS_PACKET_HEADER_SIZE);
410
411         p->rindex = idx;
412 }
413
414 int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
415         const void *d;
416         int r;
417
418         assert(p);
419
420         r = dns_packet_read(p, sizeof(uint8_t), &d, start);
421         if (r < 0)
422                 return r;
423
424         *ret = ((uint8_t*) d)[0];
425         return 0;
426 }
427
428 int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
429         const void *d;
430         int r;
431
432         assert(p);
433
434         r = dns_packet_read(p, sizeof(uint16_t), &d, start);
435         if (r < 0)
436                 return r;
437
438         *ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) |
439                 ((uint16_t) ((uint8_t*) d)[1]);
440         return 0;
441 }
442
443 int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
444         const void *d;
445         int r;
446
447         assert(p);
448
449         r = dns_packet_read(p, sizeof(uint32_t), &d, start);
450         if (r < 0)
451                 return r;
452
453         *ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) |
454                (((uint32_t) ((uint8_t*) d)[1]) << 16) |
455                (((uint32_t) ((uint8_t*) d)[2]) << 8) |
456                 ((uint32_t) ((uint8_t*) d)[3]);
457
458         return 0;
459 }
460
461 int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
462         size_t saved_rindex;
463         const void *d;
464         char *t;
465         uint8_t c;
466         int r;
467
468         assert(p);
469
470         saved_rindex = p->rindex;
471
472         r = dns_packet_read_uint8(p, &c, NULL);
473         if (r < 0)
474                 goto fail;
475
476         r = dns_packet_read(p, c, &d, NULL);
477         if (r < 0)
478                 goto fail;
479
480         if (memchr(d, 0, c)) {
481                 r = -EBADMSG;
482                 goto fail;
483         }
484
485         t = strndup(d, c);
486         if (!t) {
487                 r = -ENOMEM;
488                 goto fail;
489         }
490
491         if (!utf8_is_valid(t)) {
492                 free(t);
493                 r = -EBADMSG;
494                 goto fail;
495         }
496
497         *ret = t;
498
499         if (start)
500                 *start = saved_rindex;
501
502         return 0;
503
504 fail:
505         dns_packet_rewind(p, saved_rindex);
506         return r;
507 }
508
509 int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
510         size_t saved_rindex, after_rindex = 0;
511         _cleanup_free_ char *ret = NULL;
512         size_t n = 0, allocated = 0;
513         bool first = true;
514         int r;
515
516         assert(p);
517         assert(_ret);
518
519         saved_rindex = p->rindex;
520
521         for (;;) {
522                 uint8_t c, d;
523
524                 r = dns_packet_read_uint8(p, &c, NULL);
525                 if (r < 0)
526                         goto fail;
527
528                 if (c == 0)
529                         /* End of name */
530                         break;
531                 else if (c <= 63) {
532                         _cleanup_free_ char *t = NULL;
533                         const char *label;
534
535                         /* Literal label */
536                         r = dns_packet_read(p, c, (const void**) &label, NULL);
537                         if (r < 0)
538                                 goto fail;
539
540                         r = dns_label_escape(label, c, &t);
541                         if (r < 0)
542                                 goto fail;
543
544                         if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
545                                 r = -ENOMEM;
546                                 goto fail;
547                         }
548
549                         if (!first)
550                                 ret[n++] = '.';
551                         else
552                                 first = false;
553
554                         memcpy(ret + n, t, c);
555                         n += r;
556                         continue;
557                 } else if ((c & 0xc0) == 0xc0) {
558                         uint16_t ptr;
559
560                         /* Pointer */
561                         r = dns_packet_read_uint8(p, &d, NULL);
562                         if (r < 0)
563                                 goto fail;
564
565                         ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
566                         if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) {
567                                 r = -EBADMSG;
568                                 goto fail;
569                         }
570
571                         if (after_rindex == 0)
572                                 after_rindex = p->rindex;
573
574                         p->rindex = ptr;
575                 } else
576                         goto fail;
577         }
578
579         if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
580                 r = -ENOMEM;
581                 goto fail;
582         }
583
584         ret[n] = 0;
585
586         if (after_rindex != 0)
587                 p->rindex= after_rindex;
588
589         *_ret = ret;
590         ret = NULL;
591
592         if (start)
593                 *start = saved_rindex;
594
595         return 0;
596
597 fail:
598         dns_packet_rewind(p, saved_rindex);
599         return r;
600 }
601
602 int dns_packet_read_key(DnsPacket *p, DnsResourceKey *ret, size_t *start) {
603         _cleanup_(dns_resource_key_free) DnsResourceKey k = {};
604         size_t saved_rindex;
605         int r;
606
607         assert(p);
608         assert(ret);
609
610         saved_rindex = p->rindex;
611
612         r = dns_packet_read_name(p, &k.name, NULL);
613         if (r < 0)
614                 goto fail;
615
616         r = dns_packet_read_uint16(p, &k.type, NULL);
617         if (r < 0)
618                 goto fail;
619
620         r = dns_packet_read_uint16(p, &k.class, NULL);
621         if (r < 0)
622                 goto fail;
623
624         *ret = k;
625         zero(k);
626
627         if (start)
628                 *start = saved_rindex;
629
630         return 0;
631 fail:
632         dns_packet_rewind(p, saved_rindex);
633         return r;
634 }
635
636 int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
637         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr;
638         size_t saved_rindex, offset;
639         uint16_t rdlength;
640         const void *d;
641         int r;
642
643         assert(p);
644         assert(ret);
645
646         rr = dns_resource_record_new();
647         if (!rr)
648                 return -ENOMEM;
649
650         saved_rindex = p->rindex;
651
652         r = dns_packet_read_key(p, &rr->key, NULL);
653         if (r < 0)
654                 goto fail;
655
656         r = dns_packet_read_uint32(p, &rr->ttl, NULL);
657         if (r < 0)
658                 goto fail;
659
660         r = dns_packet_read_uint16(p, &rdlength, NULL);
661         if (r < 0)
662                 goto fail;
663
664         if (p->rindex + rdlength > p->size) {
665                 r = -EBADMSG;
666                 goto fail;
667         }
668
669         offset = p->rindex;
670
671         switch (rr->key.type) {
672
673         case DNS_TYPE_PTR:
674         case DNS_TYPE_NS:
675         case DNS_TYPE_CNAME:
676                 r = dns_packet_read_name(p, &rr->ptr.name, NULL);
677                 break;
678
679         case DNS_TYPE_HINFO:
680                 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
681                 if (r < 0)
682                         goto fail;
683
684                 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
685                 break;
686
687         case DNS_TYPE_A:
688                 r = dns_packet_read(p, sizeof(struct in_addr), &d, NULL);
689                 if (r < 0)
690                         goto fail;
691
692                 memcpy(&rr->a.in_addr, d, sizeof(struct in_addr));
693                 break;
694
695         case DNS_TYPE_AAAA:
696                 r = dns_packet_read(p, sizeof(struct in6_addr), &d, NULL);
697                 if (r < 0)
698                         goto fail;
699
700                 memcpy(&rr->aaaa.in6_addr, d, sizeof(struct in6_addr));
701                 break;
702
703         default:
704                 r = dns_packet_read(p, rdlength, &d, NULL);
705                 if (r < 0)
706                         goto fail;
707
708                 rr->generic.data = memdup(d, rdlength);
709                 if (!rr->generic.data) {
710                         r = -ENOMEM;
711                         goto fail;
712                 }
713
714                 rr->generic.size = rdlength;
715                 break;
716         }
717         if (r < 0)
718                 goto fail;
719         if (p->rindex != offset + rdlength) {
720                 r = -EBADMSG;
721                 goto fail;
722         }
723
724         *ret = rr;
725         rr = NULL;
726
727         if (start)
728                 *start = saved_rindex;
729
730         return 0;
731 fail:
732         dns_packet_rewind(p, saved_rindex);
733         return r;
734 }
735
736 int dns_packet_skip_question(DnsPacket *p) {
737         unsigned i, n;
738         int r;
739
740         assert(p);
741
742         dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
743
744         n = DNS_PACKET_QDCOUNT(p);
745         for (i = 0; i < n; i++) {
746                 _cleanup_(dns_resource_key_free) DnsResourceKey key = {};
747
748                 r = dns_packet_read_key(p, &key, NULL);
749                 if (r < 0)
750                         return r;
751         }
752
753         return 0;
754 }
755
756 int dns_packet_extract_rrs(DnsPacket *p) {
757         DnsResourceRecord **rrs = NULL;
758         size_t saved_rindex;
759         unsigned n, added = 0;
760         int r;
761
762         if (p->rrs)
763                 return (int) DNS_PACKET_RRCOUNT(p);
764
765         saved_rindex = p->rindex;
766
767         r = dns_packet_skip_question(p);
768         if (r < 0)
769                 goto finish;
770
771         n = DNS_PACKET_RRCOUNT(p);
772         if (n <= 0) {
773                 r = 0;
774                 goto finish;
775         }
776
777         rrs = new0(DnsResourceRecord*, n);
778         if (!rrs) {
779                 r = -ENOMEM;
780                 goto finish;
781         }
782
783         for (added = 0; added < n; added++) {
784                 r = dns_packet_read_rr(p, &rrs[added], NULL);
785                 if (r < 0) {
786                         dns_resource_record_freev(rrs, added);
787                         goto finish;
788                 }
789         }
790
791         p->rrs = rrs;
792         r = (int) n;
793
794 finish:
795         p->rindex = saved_rindex;
796         return r;
797 }
798
799 static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
800         [DNS_RCODE_SUCCESS] = "SUCCESS",
801         [DNS_RCODE_FORMERR] = "FORMERR",
802         [DNS_RCODE_SERVFAIL] = "SERVFAIL",
803         [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
804         [DNS_RCODE_NOTIMP] = "NOTIMP",
805         [DNS_RCODE_REFUSED] = "REFUSED",
806         [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
807         [DNS_RCODE_YXRRSET] = "YRRSET",
808         [DNS_RCODE_NXRRSET] = "NXRRSET",
809         [DNS_RCODE_NOTAUTH] = "NOTAUTH",
810         [DNS_RCODE_NOTZONE] = "NOTZONE",
811         [DNS_RCODE_BADVERS] = "BADVERS",
812         [DNS_RCODE_BADKEY] = "BADKEY",
813         [DNS_RCODE_BADTIME] = "BADTIME",
814         [DNS_RCODE_BADMODE] = "BADMODE",
815         [DNS_RCODE_BADNAME] = "BADNAME",
816         [DNS_RCODE_BADALG] = "BADALG",
817         [DNS_RCODE_BADTRUNC] = "BADTRUNC",
818 };
819 DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);
820
821 static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
822         [DNS_PROTOCOL_DNS] = "dns",
823         [DNS_PROTOCOL_MDNS] = "mdns",
824         [DNS_PROTOCOL_LLMNR] = "llmnr",
825 };
826 DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);