]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-packet.c
nss-myhostname: don't include assert.h twice
[thirdparty/systemd.git] / src / resolve / resolved-dns-packet.c
CommitLineData
74b2466e
LP
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"
c73ce96b 23#include "util.h"
74b2466e
LP
24#include "resolved-dns-domain.h"
25#include "resolved-dns-packet.h"
26
1716f6dc 27int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
74b2466e
LP
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
c73ce96b
LP
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
74b2466e
LP
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;
1716f6dc 54 p->protocol = protocol;
74b2466e
LP
55 p->n_ref = 1;
56
57 *ret = p;
58
59 return 0;
60}
61
1716f6dc 62int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
74b2466e
LP
63 DnsPacket *p;
64 DnsPacketHeader *h;
65 int r;
66
67 assert(ret);
68
1716f6dc 69 r = dns_packet_new(&p, protocol, mtu);
74b2466e
LP
70 if (r < 0)
71 return r;
72
73 h = DNS_PACKET_HEADER(p);
1716f6dc
LP
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));
74b2466e
LP
79
80 *ret = p;
81 return 0;
82}
83
84DnsPacket *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
94static void dns_packet_free(DnsPacket *p) {
95 char *s;
96
97 assert(p);
98
322345fd
LP
99 if (p->rrs)
100 dns_resource_record_freev(p->rrs, DNS_PACKET_RRCOUNT(p));
101
74b2466e
LP
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
110DnsPacket *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
124int dns_packet_validate(DnsPacket *p) {
125 assert(p);
126
127 if (p->size < DNS_PACKET_HEADER_SIZE)
128 return -EBADMSG;
129
c73ce96b
LP
130 if (p->size > DNS_PACKET_SIZE_MAX)
131 return -EBADMSG;
132
74b2466e
LP
133 return 0;
134}
135
136int dns_packet_validate_reply(DnsPacket *p) {
74b2466e
LP
137 int r;
138
139 assert(p);
140
141 r = dns_packet_validate(p);
142 if (r < 0)
143 return r;
144
3cb10d3a 145 if (DNS_PACKET_QR(p) == 0)
74b2466e
LP
146 return -EBADMSG;
147
3cb10d3a 148 if (DNS_PACKET_OPCODE(p) != 0)
74b2466e
LP
149 return -EBADMSG;
150
151 return 0;
152}
153
154static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
155 assert(p);
156
c73ce96b
LP
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 }
74b2466e
LP
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
197static 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
219int 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
234int 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
250int 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
272int 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
292int 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
348done:
349 if (start)
350 *start = saved_size;
351
352 return 0;
353
354fail:
355 dns_packet_truncate(p, saved_size);
356 return r;
357}
358
359int 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
385fail:
386 dns_packet_truncate(p, saved_size);
387 return r;
388}
389
390int 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
8ba9fd9c 406void dns_packet_rewind(DnsPacket *p, size_t idx) {
74b2466e
LP
407 assert(p);
408 assert(idx <= p->size);
409 assert(idx >= DNS_PACKET_HEADER_SIZE);
410
411 p->rindex = idx;
412}
413
414int 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
428int 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
443int 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
461int 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
504fail:
505 dns_packet_rewind(p, saved_rindex);
506 return r;
507}
508
509int 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
597fail:
598 dns_packet_rewind(p, saved_rindex);
599 return r;
600}
601
602int 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;
631fail:
632 dns_packet_rewind(p, saved_rindex);
633 return r;
634}
635
636int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
4e0296a9 637 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr;
74b2466e
LP
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
74b2466e
LP
646 rr = dns_resource_record_new();
647 if (!rr)
4e0296a9
ZJS
648 return -ENOMEM;
649
650 saved_rindex = p->rindex;
74b2466e
LP
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;
731fail:
732 dns_packet_rewind(p, saved_rindex);
733 return r;
734}
735
736int dns_packet_skip_question(DnsPacket *p) {
322345fd 737 unsigned i, n;
74b2466e
LP
738 int r;
739
74b2466e
LP
740 assert(p);
741
322345fd
LP
742 dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
743
3cb10d3a 744 n = DNS_PACKET_QDCOUNT(p);
74b2466e
LP
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
322345fd
LP
756int 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
794finish:
795 p->rindex = saved_rindex;
796 return r;
797}
798
74b2466e
LP
799static 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};
819DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);
1716f6dc
LP
820
821static 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};
826DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);