]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-packet.c
missing.h: add IFLA_MACVLAN_FLAGS
[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
27int dns_packet_new(DnsPacket **ret, 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
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;
54 p->n_ref = 1;
55
56 *ret = p;
57
58 return 0;
59}
60
61int dns_packet_new_query(DnsPacket **ret, size_t mtu) {
62 DnsPacket *p;
63 DnsPacketHeader *h;
64 int r;
65
66 assert(ret);
67
68 r = dns_packet_new(&p, mtu);
69 if (r < 0)
70 return r;
71
72 h = DNS_PACKET_HEADER(p);
73 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, 0));
74
75 *ret = p;
76 return 0;
77}
78
79DnsPacket *dns_packet_ref(DnsPacket *p) {
80
81 if (!p)
82 return NULL;
83
84 assert(p->n_ref > 0);
85 p->n_ref++;
86 return p;
87}
88
89static void dns_packet_free(DnsPacket *p) {
90 char *s;
91
92 assert(p);
93
94 while ((s = hashmap_steal_first_key(p->names)))
95 free(s);
96 hashmap_free(p->names);
97
98 free(p->data);
99 free(p);
100}
101
102DnsPacket *dns_packet_unref(DnsPacket *p) {
103 if (!p)
104 return NULL;
105
106 assert(p->n_ref > 0);
107
108 if (p->n_ref == 1)
109 dns_packet_free(p);
110 else
111 p->n_ref--;
112
113 return NULL;
114}
115
116int dns_packet_validate(DnsPacket *p) {
117 assert(p);
118
119 if (p->size < DNS_PACKET_HEADER_SIZE)
120 return -EBADMSG;
121
c73ce96b
LP
122 if (p->size > DNS_PACKET_SIZE_MAX)
123 return -EBADMSG;
124
74b2466e
LP
125 return 0;
126}
127
128int dns_packet_validate_reply(DnsPacket *p) {
74b2466e
LP
129 int r;
130
131 assert(p);
132
133 r = dns_packet_validate(p);
134 if (r < 0)
135 return r;
136
3cb10d3a 137 if (DNS_PACKET_QR(p) == 0)
74b2466e
LP
138 return -EBADMSG;
139
3cb10d3a 140 if (DNS_PACKET_OPCODE(p) != 0)
74b2466e
LP
141 return -EBADMSG;
142
143 return 0;
144}
145
146static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
147 assert(p);
148
c73ce96b
LP
149 if (p->size + add > p->allocated) {
150 size_t a;
151
152 a = PAGE_ALIGN((p->size + add) * 2);
153 if (a > DNS_PACKET_SIZE_MAX)
154 a = DNS_PACKET_SIZE_MAX;
155
156 if (p->size + add > a)
157 return -EMSGSIZE;
158
159 if (p->data) {
160 void *d;
161
162 d = realloc(p->data, a);
163 if (!d)
164 return -ENOMEM;
165
166 p->data = d;
167 } else {
168 p->data = malloc(a);
169 if (!p->data)
170 return -ENOMEM;
171
172 memcpy(p->data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size);
173 memzero((uint8_t*) p->data + p->size, a - p->size);
174 }
175
176 p->allocated = a;
177 }
74b2466e
LP
178
179 if (start)
180 *start = p->size;
181
182 if (ret)
183 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size;
184
185 p->size += add;
186 return 0;
187}
188
189static void dns_packet_truncate(DnsPacket *p, size_t sz) {
190 Iterator i;
191 char *s;
192 void *n;
193
194 assert(p);
195
196 if (p->size <= sz)
197 return;
198
199 HASHMAP_FOREACH_KEY(s, n, p->names, i) {
200
201 if (PTR_TO_SIZE(n) < sz)
202 continue;
203
204 hashmap_remove(p->names, s);
205 free(s);
206 }
207
208 p->size = sz;
209}
210
211int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) {
212 void *d;
213 int r;
214
215 assert(p);
216
217 r = dns_packet_extend(p, sizeof(uint8_t), &d, start);
218 if (r < 0)
219 return r;
220
221 ((uint8_t*) d)[0] = v;
222
223 return 0;
224}
225
226int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
227 void *d;
228 int r;
229
230 assert(p);
231
232 r = dns_packet_extend(p, sizeof(uint16_t), &d, start);
233 if (r < 0)
234 return r;
235
236 ((uint8_t*) d)[0] = (uint8_t) (v >> 8);
237 ((uint8_t*) d)[1] = (uint8_t) (v & 255);
238
239 return 0;
240}
241
242int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
243 void *d;
244 size_t l;
245 int r;
246
247 assert(p);
248 assert(s);
249
250 l = strlen(s);
251 if (l > 255)
252 return -E2BIG;
253
254 r = dns_packet_extend(p, 1 + l, &d, start);
255 if (r < 0)
256 return r;
257
258 ((uint8_t*) d)[0] = (uint8_t) l;
259 memcpy(((uint8_t*) d) + 1, s, l);
260
261 return 0;
262}
263
264int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
265 void *w;
266 int r;
267
268 assert(p);
269 assert(d);
270
271 if (l > DNS_LABEL_MAX)
272 return -E2BIG;
273
274 r = dns_packet_extend(p, 1 + l, &w, start);
275 if (r < 0)
276 return r;
277
278 ((uint8_t*) w)[0] = (uint8_t) l;
279 memcpy(((uint8_t*) w) + 1, d, l);
280
281 return 0;
282}
283
284int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
285 size_t saved_size;
286 int r;
287
288 assert(p);
289 assert(name);
290
291 saved_size = p->size;
292
293 while (*name) {
294 _cleanup_free_ char *s = NULL;
295 char label[DNS_LABEL_MAX];
296 size_t n;
297
298 n = PTR_TO_SIZE(hashmap_get(p->names, name));
299 if (n > 0) {
300 assert(n < p->size);
301
302 if (n < 0x4000) {
303 r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
304 if (r < 0)
305 goto fail;
306
307 goto done;
308 }
309 }
310
311 s = strdup(name);
312 if (!s) {
313 r = -ENOMEM;
314 goto fail;
315 }
316
317 r = dns_label_unescape(&name, label, sizeof(label));
318 if (r < 0)
319 goto fail;
320
321 r = dns_packet_append_label(p, label, r, &n);
322 if (r < 0)
323 goto fail;
324
325 r = hashmap_ensure_allocated(&p->names, dns_name_hash_func, dns_name_compare_func);
326 if (r < 0)
327 goto fail;
328
329 r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
330 if (r < 0)
331 goto fail;
332
333 s = NULL;
334 }
335
336 r = dns_packet_append_uint8(p, 0, NULL);
337 if (r < 0)
338 return r;
339
340done:
341 if (start)
342 *start = saved_size;
343
344 return 0;
345
346fail:
347 dns_packet_truncate(p, saved_size);
348 return r;
349}
350
351int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
352 size_t saved_size;
353 int r;
354
355 assert(p);
356 assert(k);
357
358 saved_size = p->size;
359
360 r = dns_packet_append_name(p, k->name, NULL);
361 if (r < 0)
362 goto fail;
363
364 r = dns_packet_append_uint16(p, k->type, NULL);
365 if (r < 0)
366 goto fail;
367
368 r = dns_packet_append_uint16(p, k->class, NULL);
369 if (r < 0)
370 goto fail;
371
372 if (start)
373 *start = saved_size;
374
375 return 0;
376
377fail:
378 dns_packet_truncate(p, saved_size);
379 return r;
380}
381
382int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
383 assert(p);
384
385 if (p->rindex + sz > p->size)
386 return -EMSGSIZE;
387
388 if (ret)
389 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
390
391 if (start)
392 *start = p->rindex;
393
394 p->rindex += sz;
395 return 0;
396}
397
398static void dns_packet_rewind(DnsPacket *p, size_t idx) {
399 assert(p);
400 assert(idx <= p->size);
401 assert(idx >= DNS_PACKET_HEADER_SIZE);
402
403 p->rindex = idx;
404}
405
406int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
407 const void *d;
408 int r;
409
410 assert(p);
411
412 r = dns_packet_read(p, sizeof(uint8_t), &d, start);
413 if (r < 0)
414 return r;
415
416 *ret = ((uint8_t*) d)[0];
417 return 0;
418}
419
420int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
421 const void *d;
422 int r;
423
424 assert(p);
425
426 r = dns_packet_read(p, sizeof(uint16_t), &d, start);
427 if (r < 0)
428 return r;
429
430 *ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) |
431 ((uint16_t) ((uint8_t*) d)[1]);
432 return 0;
433}
434
435int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
436 const void *d;
437 int r;
438
439 assert(p);
440
441 r = dns_packet_read(p, sizeof(uint32_t), &d, start);
442 if (r < 0)
443 return r;
444
445 *ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) |
446 (((uint32_t) ((uint8_t*) d)[1]) << 16) |
447 (((uint32_t) ((uint8_t*) d)[2]) << 8) |
448 ((uint32_t) ((uint8_t*) d)[3]);
449
450 return 0;
451}
452
453int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
454 size_t saved_rindex;
455 const void *d;
456 char *t;
457 uint8_t c;
458 int r;
459
460 assert(p);
461
462 saved_rindex = p->rindex;
463
464 r = dns_packet_read_uint8(p, &c, NULL);
465 if (r < 0)
466 goto fail;
467
468 r = dns_packet_read(p, c, &d, NULL);
469 if (r < 0)
470 goto fail;
471
472 if (memchr(d, 0, c)) {
473 r = -EBADMSG;
474 goto fail;
475 }
476
477 t = strndup(d, c);
478 if (!t) {
479 r = -ENOMEM;
480 goto fail;
481 }
482
483 if (!utf8_is_valid(t)) {
484 free(t);
485 r = -EBADMSG;
486 goto fail;
487 }
488
489 *ret = t;
490
491 if (start)
492 *start = saved_rindex;
493
494 return 0;
495
496fail:
497 dns_packet_rewind(p, saved_rindex);
498 return r;
499}
500
501int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
502 size_t saved_rindex, after_rindex = 0;
503 _cleanup_free_ char *ret = NULL;
504 size_t n = 0, allocated = 0;
505 bool first = true;
506 int r;
507
508 assert(p);
509 assert(_ret);
510
511 saved_rindex = p->rindex;
512
513 for (;;) {
514 uint8_t c, d;
515
516 r = dns_packet_read_uint8(p, &c, NULL);
517 if (r < 0)
518 goto fail;
519
520 if (c == 0)
521 /* End of name */
522 break;
523 else if (c <= 63) {
524 _cleanup_free_ char *t = NULL;
525 const char *label;
526
527 /* Literal label */
528 r = dns_packet_read(p, c, (const void**) &label, NULL);
529 if (r < 0)
530 goto fail;
531
532 r = dns_label_escape(label, c, &t);
533 if (r < 0)
534 goto fail;
535
536 if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
537 r = -ENOMEM;
538 goto fail;
539 }
540
541 if (!first)
542 ret[n++] = '.';
543 else
544 first = false;
545
546 memcpy(ret + n, t, c);
547 n += r;
548 continue;
549 } else if ((c & 0xc0) == 0xc0) {
550 uint16_t ptr;
551
552 /* Pointer */
553 r = dns_packet_read_uint8(p, &d, NULL);
554 if (r < 0)
555 goto fail;
556
557 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
558 if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) {
559 r = -EBADMSG;
560 goto fail;
561 }
562
563 if (after_rindex == 0)
564 after_rindex = p->rindex;
565
566 p->rindex = ptr;
567 } else
568 goto fail;
569 }
570
571 if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
572 r = -ENOMEM;
573 goto fail;
574 }
575
576 ret[n] = 0;
577
578 if (after_rindex != 0)
579 p->rindex= after_rindex;
580
581 *_ret = ret;
582 ret = NULL;
583
584 if (start)
585 *start = saved_rindex;
586
587 return 0;
588
589fail:
590 dns_packet_rewind(p, saved_rindex);
591 return r;
592}
593
594int dns_packet_read_key(DnsPacket *p, DnsResourceKey *ret, size_t *start) {
595 _cleanup_(dns_resource_key_free) DnsResourceKey k = {};
596 size_t saved_rindex;
597 int r;
598
599 assert(p);
600 assert(ret);
601
602 saved_rindex = p->rindex;
603
604 r = dns_packet_read_name(p, &k.name, NULL);
605 if (r < 0)
606 goto fail;
607
608 r = dns_packet_read_uint16(p, &k.type, NULL);
609 if (r < 0)
610 goto fail;
611
612 r = dns_packet_read_uint16(p, &k.class, NULL);
613 if (r < 0)
614 goto fail;
615
616 *ret = k;
617 zero(k);
618
619 if (start)
620 *start = saved_rindex;
621
622 return 0;
623fail:
624 dns_packet_rewind(p, saved_rindex);
625 return r;
626}
627
628int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
4e0296a9 629 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr;
74b2466e
LP
630 size_t saved_rindex, offset;
631 uint16_t rdlength;
632 const void *d;
633 int r;
634
635 assert(p);
636 assert(ret);
637
74b2466e
LP
638 rr = dns_resource_record_new();
639 if (!rr)
4e0296a9
ZJS
640 return -ENOMEM;
641
642 saved_rindex = p->rindex;
74b2466e
LP
643
644 r = dns_packet_read_key(p, &rr->key, NULL);
645 if (r < 0)
646 goto fail;
647
648 r = dns_packet_read_uint32(p, &rr->ttl, NULL);
649 if (r < 0)
650 goto fail;
651
652 r = dns_packet_read_uint16(p, &rdlength, NULL);
653 if (r < 0)
654 goto fail;
655
656 if (p->rindex + rdlength > p->size) {
657 r = -EBADMSG;
658 goto fail;
659 }
660
661 offset = p->rindex;
662
663 switch (rr->key.type) {
664
665 case DNS_TYPE_PTR:
666 case DNS_TYPE_NS:
667 case DNS_TYPE_CNAME:
668 r = dns_packet_read_name(p, &rr->ptr.name, NULL);
669 break;
670
671 case DNS_TYPE_HINFO:
672 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
673 if (r < 0)
674 goto fail;
675
676 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
677 break;
678
679 case DNS_TYPE_A:
680 r = dns_packet_read(p, sizeof(struct in_addr), &d, NULL);
681 if (r < 0)
682 goto fail;
683
684 memcpy(&rr->a.in_addr, d, sizeof(struct in_addr));
685 break;
686
687 case DNS_TYPE_AAAA:
688 r = dns_packet_read(p, sizeof(struct in6_addr), &d, NULL);
689 if (r < 0)
690 goto fail;
691
692 memcpy(&rr->aaaa.in6_addr, d, sizeof(struct in6_addr));
693 break;
694
695 default:
696 r = dns_packet_read(p, rdlength, &d, NULL);
697 if (r < 0)
698 goto fail;
699
700 rr->generic.data = memdup(d, rdlength);
701 if (!rr->generic.data) {
702 r = -ENOMEM;
703 goto fail;
704 }
705
706 rr->generic.size = rdlength;
707 break;
708 }
709 if (r < 0)
710 goto fail;
711 if (p->rindex != offset + rdlength) {
712 r = -EBADMSG;
713 goto fail;
714 }
715
716 *ret = rr;
717 rr = NULL;
718
719 if (start)
720 *start = saved_rindex;
721
722 return 0;
723fail:
724 dns_packet_rewind(p, saved_rindex);
725 return r;
726}
727
728int dns_packet_skip_question(DnsPacket *p) {
729 int r;
730
731 unsigned i, n;
732 assert(p);
733
3cb10d3a 734 n = DNS_PACKET_QDCOUNT(p);
74b2466e
LP
735 for (i = 0; i < n; i++) {
736 _cleanup_(dns_resource_key_free) DnsResourceKey key = {};
737
738 r = dns_packet_read_key(p, &key, NULL);
739 if (r < 0)
740 return r;
741 }
742
743 return 0;
744}
745
746static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
747 [DNS_RCODE_SUCCESS] = "SUCCESS",
748 [DNS_RCODE_FORMERR] = "FORMERR",
749 [DNS_RCODE_SERVFAIL] = "SERVFAIL",
750 [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
751 [DNS_RCODE_NOTIMP] = "NOTIMP",
752 [DNS_RCODE_REFUSED] = "REFUSED",
753 [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
754 [DNS_RCODE_YXRRSET] = "YRRSET",
755 [DNS_RCODE_NXRRSET] = "NXRRSET",
756 [DNS_RCODE_NOTAUTH] = "NOTAUTH",
757 [DNS_RCODE_NOTZONE] = "NOTZONE",
758 [DNS_RCODE_BADVERS] = "BADVERS",
759 [DNS_RCODE_BADKEY] = "BADKEY",
760 [DNS_RCODE_BADTIME] = "BADTIME",
761 [DNS_RCODE_BADMODE] = "BADMODE",
762 [DNS_RCODE_BADNAME] = "BADNAME",
763 [DNS_RCODE_BADALG] = "BADALG",
764 [DNS_RCODE_BADTRUNC] = "BADTRUNC",
765};
766DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);