]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-packet.c
hashmap: introduce hash_ops to make struct Hashmap smaller
[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"
2e276efc 24#include "strv.h"
74b2466e
LP
25#include "resolved-dns-domain.h"
26#include "resolved-dns-packet.h"
27
1716f6dc 28int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
74b2466e
LP
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
c73ce96b
LP
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
74b2466e
LP
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;
1716f6dc 55 p->protocol = protocol;
74b2466e
LP
56 p->n_ref = 1;
57
58 *ret = p;
59
60 return 0;
61}
62
1716f6dc 63int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
74b2466e
LP
64 DnsPacket *p;
65 DnsPacketHeader *h;
66 int r;
67
68 assert(ret);
69
1716f6dc 70 r = dns_packet_new(&p, protocol, mtu);
74b2466e
LP
71 if (r < 0)
72 return r;
73
74 h = DNS_PACKET_HEADER(p);
1716f6dc 75
ea917db9
LP
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 */));
1716f6dc 86 else
ea917db9
LP
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 */));
74b2466e
LP
96
97 *ret = p;
98 return 0;
99}
100
101DnsPacket *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
111static void dns_packet_free(DnsPacket *p) {
112 char *s;
113
114 assert(p);
115
faa133f3
LP
116 dns_question_unref(p->question);
117 dns_answer_unref(p->answer);
322345fd 118
74b2466e
LP
119 while ((s = hashmap_steal_first_key(p->names)))
120 free(s);
121 hashmap_free(p->names);
122
faa133f3 123 free(p->_data);
74b2466e
LP
124 free(p);
125}
126
127DnsPacket *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
141int dns_packet_validate(DnsPacket *p) {
142 assert(p);
143
144 if (p->size < DNS_PACKET_HEADER_SIZE)
145 return -EBADMSG;
146
c73ce96b
LP
147 if (p->size > DNS_PACKET_SIZE_MAX)
148 return -EBADMSG;
149
623a4c97 150 return 1;
74b2466e
LP
151}
152
153int dns_packet_validate_reply(DnsPacket *p) {
74b2466e
LP
154 int r;
155
156 assert(p);
157
158 r = dns_packet_validate(p);
159 if (r < 0)
160 return r;
161
623a4c97
LP
162 if (DNS_PACKET_QR(p) != 1)
163 return 0;
164
165 if (DNS_PACKET_OPCODE(p) != 0)
74b2466e
LP
166 return -EBADMSG;
167
ea917db9
LP
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
623a4c97
LP
173 return 1;
174}
175
176int 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
3cb10d3a 188 if (DNS_PACKET_OPCODE(p) != 0)
74b2466e
LP
189 return -EBADMSG;
190
623a4c97
LP
191 if (DNS_PACKET_TC(p))
192 return -EBADMSG;
193
ea917db9 194 /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */
623a4c97
LP
195 if (p->protocol == DNS_PROTOCOL_LLMNR &&
196 DNS_PACKET_QDCOUNT(p) != 1)
197 return -EBADMSG;
198
ea917db9 199 /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */
623a4c97
LP
200 if (DNS_PACKET_ANCOUNT(p) > 0)
201 return -EBADMSG;
202
ea917db9 203 /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */
623a4c97
LP
204 if (DNS_PACKET_NSCOUNT(p) > 0)
205 return -EBADMSG;
206
207 return 1;
74b2466e
LP
208}
209
210static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
211 assert(p);
212
c73ce96b
LP
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
faa133f3 223 if (p->_data) {
c73ce96b
LP
224 void *d;
225
faa133f3 226 d = realloc(p->_data, a);
c73ce96b
LP
227 if (!d)
228 return -ENOMEM;
229
faa133f3 230 p->_data = d;
c73ce96b 231 } else {
faa133f3
LP
232 p->_data = malloc(a);
233 if (!p->_data)
c73ce96b
LP
234 return -ENOMEM;
235
faa133f3
LP
236 memcpy(p->_data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size);
237 memzero((uint8_t*) p->_data + p->size, a - p->size);
c73ce96b
LP
238 }
239
240 p->allocated = a;
241 }
74b2466e
LP
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
253static 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
623a4c97
LP
275int 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
74b2466e
LP
289int 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
304int 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);
623a4c97
LP
315 ((uint8_t*) d)[1] = (uint8_t) v;
316
317 return 0;
318}
319
320int 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;
74b2466e
LP
334
335 return 0;
336}
337
338int 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
360int 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
151226ab
ZJS
380int dns_packet_append_name(DnsPacket *p, const char *name,
381 bool allow_compression, size_t *start) {
74b2466e
LP
382 size_t saved_size;
383 int r;
384
385 assert(p);
386 assert(name);
387
388 saved_size = p->size;
389
390 while (*name) {
391 _cleanup_free_ char *s = NULL;
392 char label[DNS_LABEL_MAX];
151226ab 393 size_t n = 0;
bdf10b5b 394 int k;
74b2466e 395
151226ab
ZJS
396 if (allow_compression)
397 n = PTR_TO_SIZE(hashmap_get(p->names, name));
74b2466e
LP
398 if (n > 0) {
399 assert(n < p->size);
400
401 if (n < 0x4000) {
402 r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
403 if (r < 0)
404 goto fail;
405
406 goto done;
407 }
408 }
409
410 s = strdup(name);
411 if (!s) {
412 r = -ENOMEM;
413 goto fail;
414 }
415
416 r = dns_label_unescape(&name, label, sizeof(label));
417 if (r < 0)
418 goto fail;
419
bdf10b5b
LP
420 if (p->protocol == DNS_PROTOCOL_DNS)
421 k = dns_label_apply_idna(label, r, label, sizeof(label));
422 else
423 k = dns_label_undo_idna(label, r, label, sizeof(label));
424 if (k < 0) {
425 r = k;
426 goto fail;
427 }
428 if (k > 0)
429 r = k;
430
74b2466e
LP
431 r = dns_packet_append_label(p, label, r, &n);
432 if (r < 0)
433 goto fail;
434
151226ab 435 if (allow_compression) {
d5099efc 436 r = hashmap_ensure_allocated(&p->names, &dns_name_hash_ops);
151226ab
ZJS
437 if (r < 0)
438 goto fail;
74b2466e 439
151226ab
ZJS
440 r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
441 if (r < 0)
442 goto fail;
74b2466e 443
151226ab
ZJS
444 s = NULL;
445 }
74b2466e
LP
446 }
447
448 r = dns_packet_append_uint8(p, 0, NULL);
449 if (r < 0)
450 return r;
451
452done:
453 if (start)
454 *start = saved_size;
455
456 return 0;
457
458fail:
459 dns_packet_truncate(p, saved_size);
460 return r;
461}
462
463int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
464 size_t saved_size;
465 int r;
466
467 assert(p);
468 assert(k);
469
470 saved_size = p->size;
471
151226ab 472 r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, NULL);
74b2466e
LP
473 if (r < 0)
474 goto fail;
475
476 r = dns_packet_append_uint16(p, k->type, NULL);
477 if (r < 0)
478 goto fail;
479
480 r = dns_packet_append_uint16(p, k->class, NULL);
481 if (r < 0)
482 goto fail;
483
484 if (start)
485 *start = saved_size;
486
487 return 0;
488
489fail:
490 dns_packet_truncate(p, saved_size);
491 return r;
492}
493
623a4c97
LP
494int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) {
495 size_t saved_size, rdlength_offset, end, rdlength;
496 int r;
497
498 assert(p);
499 assert(rr);
500
501 saved_size = p->size;
502
503 r = dns_packet_append_key(p, rr->key, NULL);
504 if (r < 0)
505 goto fail;
506
507 r = dns_packet_append_uint32(p, rr->ttl, NULL);
508 if (r < 0)
509 goto fail;
510
511 /* Initially we write 0 here */
512 r = dns_packet_append_uint16(p, 0, &rdlength_offset);
513 if (r < 0)
514 goto fail;
515
0dae31d4 516 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
623a4c97 517
9c92ce6d
LP
518 case DNS_TYPE_SRV:
519 r = dns_packet_append_uint16(p, rr->srv.priority, NULL);
520 if (r < 0)
521 goto fail;
522
523 r = dns_packet_append_uint16(p, rr->srv.weight, NULL);
524 if (r < 0)
525 goto fail;
526
527 r = dns_packet_append_uint16(p, rr->srv.port, NULL);
528 if (r < 0)
529 goto fail;
530
151226ab 531 r = dns_packet_append_name(p, rr->srv.name, true, NULL);
9c92ce6d
LP
532 break;
533
623a4c97
LP
534 case DNS_TYPE_PTR:
535 case DNS_TYPE_NS:
536 case DNS_TYPE_CNAME:
8ac4e9e1 537 case DNS_TYPE_DNAME:
151226ab 538 r = dns_packet_append_name(p, rr->ptr.name, true, NULL);
623a4c97
LP
539 break;
540
541 case DNS_TYPE_HINFO:
542 r = dns_packet_append_string(p, rr->hinfo.cpu, NULL);
543 if (r < 0)
544 goto fail;
545
546 r = dns_packet_append_string(p, rr->hinfo.os, NULL);
547 break;
548
9de3e329 549 case DNS_TYPE_SPF: /* exactly the same as TXT */
2e276efc
ZJS
550 case DNS_TYPE_TXT: {
551 char **s;
552
553 STRV_FOREACH(s, rr->txt.strings) {
554 r = dns_packet_append_string(p, *s, NULL);
555 if (r < 0)
556 goto fail;
557 }
558
6a6fc3df 559 r = 0;
2e276efc
ZJS
560 break;
561 }
562
623a4c97
LP
563 case DNS_TYPE_A:
564 r = dns_packet_append_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
565 break;
566
567 case DNS_TYPE_AAAA:
568 r = dns_packet_append_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
569 break;
570
571 case DNS_TYPE_SOA:
151226ab 572 r = dns_packet_append_name(p, rr->soa.mname, true, NULL);
623a4c97
LP
573 if (r < 0)
574 goto fail;
575
151226ab 576 r = dns_packet_append_name(p, rr->soa.rname, true, NULL);
623a4c97
LP
577 if (r < 0)
578 goto fail;
579
580 r = dns_packet_append_uint32(p, rr->soa.serial, NULL);
581 if (r < 0)
582 goto fail;
583
584 r = dns_packet_append_uint32(p, rr->soa.refresh, NULL);
585 if (r < 0)
586 goto fail;
587
588 r = dns_packet_append_uint32(p, rr->soa.retry, NULL);
589 if (r < 0)
590 goto fail;
591
592 r = dns_packet_append_uint32(p, rr->soa.expire, NULL);
593 if (r < 0)
594 goto fail;
595
596 r = dns_packet_append_uint32(p, rr->soa.minimum, NULL);
597 break;
598
599 case DNS_TYPE_MX:
946c7094
ZJS
600 r = dns_packet_append_uint16(p, rr->mx.priority, NULL);
601 if (r < 0)
602 goto fail;
603
151226ab 604 r = dns_packet_append_name(p, rr->mx.exchange, true, NULL);
946c7094
ZJS
605 break;
606
0dae31d4
ZJS
607 case DNS_TYPE_LOC:
608 r = dns_packet_append_uint8(p, rr->loc.version, NULL);
609 if (r < 0)
610 goto fail;
611
612 r = dns_packet_append_uint8(p, rr->loc.size, NULL);
613 if (r < 0)
614 goto fail;
615
616 r = dns_packet_append_uint8(p, rr->loc.horiz_pre, NULL);
617 if (r < 0)
618 goto fail;
619
620 r = dns_packet_append_uint8(p, rr->loc.vert_pre, NULL);
621 if (r < 0)
622 goto fail;
623
afbc4f26 624 r = dns_packet_append_uint32(p, rr->loc.latitude, NULL);
0dae31d4
ZJS
625 if (r < 0)
626 goto fail;
627
afbc4f26 628 r = dns_packet_append_uint32(p, rr->loc.longitude, NULL);
0dae31d4
ZJS
629 if (r < 0)
630 goto fail;
631
afbc4f26 632 r = dns_packet_append_uint32(p, rr->loc.altitude, NULL);
0dae31d4
ZJS
633 break;
634
623a4c97 635 case DNS_TYPE_SSHFP:
42cc2eeb
LP
636 r = dns_packet_append_uint8(p, rr->sshfp.algorithm, NULL);
637 if (r < 0)
638 goto fail;
8db0d2f5 639
42cc2eeb
LP
640 r = dns_packet_append_uint8(p, rr->sshfp.fptype, NULL);
641 if (r < 0)
642 goto fail;
643
644 r = dns_packet_append_blob(p, rr->sshfp.key, rr->sshfp.key_size, NULL);
645 break;
646
8db0d2f5
ZJS
647 case DNS_TYPE_DNSKEY:
648 r = dns_packet_append_uint16(p, dnskey_to_flags(rr), NULL);
649 if (r < 0)
650 goto fail;
651
652 r = dns_packet_append_uint8(p, 3u, NULL);
653 if (r < 0)
654 goto fail;
655
656 r = dns_packet_append_uint8(p, rr->dnskey.algorithm, NULL);
657 if (r < 0)
658 goto fail;
659
660 r = dns_packet_append_blob(p, rr->dnskey.key, rr->dnskey.key_size, NULL);
661 break;
662
151226ab
ZJS
663 case DNS_TYPE_RRSIG:
664 r = dns_packet_append_uint16(p, rr->rrsig.type_covered, NULL);
665 if (r < 0)
666 goto fail;
667
668 r = dns_packet_append_uint8(p, rr->rrsig.algorithm, NULL);
669 if (r < 0)
670 goto fail;
671
672 r = dns_packet_append_uint8(p, rr->rrsig.labels, NULL);
673 if (r < 0)
674 goto fail;
675
676 r = dns_packet_append_uint32(p, rr->rrsig.original_ttl, NULL);
677 if (r < 0)
678 goto fail;
679
680 r = dns_packet_append_uint32(p, rr->rrsig.expiration, NULL);
681 if (r < 0)
682 goto fail;
683
684 r = dns_packet_append_uint32(p, rr->rrsig.inception, NULL);
685 if (r < 0)
686 goto fail;
687
688 r = dns_packet_append_uint8(p, rr->rrsig.key_tag, NULL);
689 if (r < 0)
690 goto fail;
691
692 r = dns_packet_append_name(p, rr->rrsig.signer, false, NULL);
693 if (r < 0)
694 goto fail;
695
696 r = dns_packet_append_blob(p, rr->rrsig.signature, rr->rrsig.signature_size, NULL);
697 break;
698
0dae31d4 699 case _DNS_TYPE_INVALID: /* unparseable */
623a4c97 700 default:
0dae31d4 701
623a4c97
LP
702 r = dns_packet_append_blob(p, rr->generic.data, rr->generic.size, NULL);
703 break;
704 }
705 if (r < 0)
706 goto fail;
707
708 /* Let's calculate the actual data size and update the field */
709 rdlength = p->size - rdlength_offset - sizeof(uint16_t);
710 if (rdlength > 0xFFFF) {
711 r = ENOSPC;
712 goto fail;
713 }
714
715 end = p->size;
716 p->size = rdlength_offset;
717 r = dns_packet_append_uint16(p, rdlength, NULL);
718 if (r < 0)
719 goto fail;
720 p->size = end;
721
351e6342
LP
722 if (start)
723 *start = saved_size;
724
623a4c97
LP
725 return 0;
726
727fail:
728 dns_packet_truncate(p, saved_size);
729 return r;
730}
731
732
74b2466e
LP
733int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
734 assert(p);
735
736 if (p->rindex + sz > p->size)
737 return -EMSGSIZE;
738
739 if (ret)
740 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
741
742 if (start)
743 *start = p->rindex;
744
745 p->rindex += sz;
746 return 0;
747}
748
8ba9fd9c 749void dns_packet_rewind(DnsPacket *p, size_t idx) {
74b2466e
LP
750 assert(p);
751 assert(idx <= p->size);
752 assert(idx >= DNS_PACKET_HEADER_SIZE);
753
754 p->rindex = idx;
755}
756
623a4c97
LP
757int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start) {
758 const void *q;
759 int r;
760
761 assert(p);
762 assert(d);
763
764 r = dns_packet_read(p, sz, &q, start);
765 if (r < 0)
766 return r;
767
768 memcpy(d, q, sz);
769 return 0;
770}
771
74b2466e
LP
772int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
773 const void *d;
774 int r;
775
776 assert(p);
777
778 r = dns_packet_read(p, sizeof(uint8_t), &d, start);
779 if (r < 0)
780 return r;
781
782 *ret = ((uint8_t*) d)[0];
783 return 0;
784}
785
786int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
787 const void *d;
788 int r;
789
790 assert(p);
791
792 r = dns_packet_read(p, sizeof(uint16_t), &d, start);
793 if (r < 0)
794 return r;
795
796 *ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) |
797 ((uint16_t) ((uint8_t*) d)[1]);
798 return 0;
799}
800
801int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
802 const void *d;
803 int r;
804
805 assert(p);
806
807 r = dns_packet_read(p, sizeof(uint32_t), &d, start);
808 if (r < 0)
809 return r;
810
811 *ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) |
812 (((uint32_t) ((uint8_t*) d)[1]) << 16) |
813 (((uint32_t) ((uint8_t*) d)[2]) << 8) |
814 ((uint32_t) ((uint8_t*) d)[3]);
815
816 return 0;
817}
818
819int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
820 size_t saved_rindex;
821 const void *d;
822 char *t;
823 uint8_t c;
824 int r;
825
826 assert(p);
827
828 saved_rindex = p->rindex;
829
830 r = dns_packet_read_uint8(p, &c, NULL);
831 if (r < 0)
832 goto fail;
833
834 r = dns_packet_read(p, c, &d, NULL);
835 if (r < 0)
836 goto fail;
837
838 if (memchr(d, 0, c)) {
839 r = -EBADMSG;
840 goto fail;
841 }
842
843 t = strndup(d, c);
844 if (!t) {
845 r = -ENOMEM;
846 goto fail;
847 }
848
849 if (!utf8_is_valid(t)) {
850 free(t);
851 r = -EBADMSG;
852 goto fail;
853 }
854
855 *ret = t;
856
857 if (start)
858 *start = saved_rindex;
859
860 return 0;
861
862fail:
863 dns_packet_rewind(p, saved_rindex);
864 return r;
865}
866
151226ab
ZJS
867int dns_packet_read_name(DnsPacket *p, char **_ret,
868 bool allow_compression, size_t *start) {
74b2466e
LP
869 size_t saved_rindex, after_rindex = 0;
870 _cleanup_free_ char *ret = NULL;
871 size_t n = 0, allocated = 0;
872 bool first = true;
873 int r;
874
875 assert(p);
876 assert(_ret);
877
878 saved_rindex = p->rindex;
879
880 for (;;) {
881 uint8_t c, d;
882
883 r = dns_packet_read_uint8(p, &c, NULL);
884 if (r < 0)
885 goto fail;
886
887 if (c == 0)
888 /* End of name */
889 break;
890 else if (c <= 63) {
891 _cleanup_free_ char *t = NULL;
892 const char *label;
893
894 /* Literal label */
895 r = dns_packet_read(p, c, (const void**) &label, NULL);
896 if (r < 0)
897 goto fail;
898
899 r = dns_label_escape(label, c, &t);
900 if (r < 0)
901 goto fail;
902
903 if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
904 r = -ENOMEM;
905 goto fail;
906 }
907
908 if (!first)
909 ret[n++] = '.';
910 else
911 first = false;
912
85818582 913 memcpy(ret + n, t, r);
74b2466e
LP
914 n += r;
915 continue;
151226ab 916 } else if (allow_compression && (c & 0xc0) == 0xc0) {
74b2466e
LP
917 uint16_t ptr;
918
919 /* Pointer */
920 r = dns_packet_read_uint8(p, &d, NULL);
921 if (r < 0)
922 goto fail;
923
924 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
925 if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) {
926 r = -EBADMSG;
927 goto fail;
928 }
929
930 if (after_rindex == 0)
931 after_rindex = p->rindex;
932
933 p->rindex = ptr;
934 } else
935 goto fail;
936 }
937
938 if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
939 r = -ENOMEM;
940 goto fail;
941 }
942
943 ret[n] = 0;
944
945 if (after_rindex != 0)
946 p->rindex= after_rindex;
947
948 *_ret = ret;
949 ret = NULL;
950
951 if (start)
952 *start = saved_rindex;
953
954 return 0;
955
956fail:
957 dns_packet_rewind(p, saved_rindex);
958 return r;
959}
960
faa133f3
LP
961int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
962 _cleanup_free_ char *name = NULL;
963 uint16_t class, type;
964 DnsResourceKey *key;
74b2466e
LP
965 size_t saved_rindex;
966 int r;
967
968 assert(p);
969 assert(ret);
970
971 saved_rindex = p->rindex;
972
151226ab 973 r = dns_packet_read_name(p, &name, true, NULL);
74b2466e
LP
974 if (r < 0)
975 goto fail;
976
faa133f3 977 r = dns_packet_read_uint16(p, &type, NULL);
74b2466e
LP
978 if (r < 0)
979 goto fail;
980
faa133f3 981 r = dns_packet_read_uint16(p, &class, NULL);
74b2466e
LP
982 if (r < 0)
983 goto fail;
984
faa133f3
LP
985 key = dns_resource_key_new_consume(class, type, name);
986 if (!key) {
987 r = -ENOMEM;
988 goto fail;
989 }
990
991 name = NULL;
992 *ret = key;
74b2466e
LP
993
994 if (start)
995 *start = saved_rindex;
996
997 return 0;
998fail:
999 dns_packet_rewind(p, saved_rindex);
1000 return r;
1001}
1002
8db0d2f5
ZJS
1003static int dns_packet_read_public_key(DnsPacket *p, size_t length,
1004 void **dp, size_t *lengthp,
1005 size_t *start) {
1006 int r;
1007 const void *d;
1008 void *d2;
1009
1010 r = dns_packet_read(p, length, &d, NULL);
1011 if (r < 0)
1012 return r;
1013
1014 d2 = memdup(d, length);
1015 if (!d2)
1016 return -ENOMEM;
1017
1018 *dp = d2;
1019 *lengthp = length;
1020 return 0;
1021}
1022
afbc4f26
ZJS
1023static bool loc_size_ok(uint8_t size) {
1024 uint8_t m = size >> 4, e = size & 0xF;
1025
1026 return m <= 9 && e <= 9 && (m > 0 || e == 0);
1027}
1028
8db0d2f5 1029static int dnskey_parse_flags(DnsResourceRecord *rr, uint16_t flags) {
3ef77d04
LP
1030 assert(rr);
1031
8db0d2f5
ZJS
1032 if (flags & ~(DNSKEY_FLAG_SEP | DNSKEY_FLAG_ZONE_KEY))
1033 return -EBADMSG;
1034
1035 rr->dnskey.zone_key_flag = flags & DNSKEY_FLAG_ZONE_KEY;
1036 rr->dnskey.sep_flag = flags & DNSKEY_FLAG_SEP;
1037 return 0;
1038}
1039
74b2466e 1040int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
faa133f3
LP
1041 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
1042 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
74b2466e
LP
1043 size_t saved_rindex, offset;
1044 uint16_t rdlength;
1045 const void *d;
1046 int r;
1047
1048 assert(p);
1049 assert(ret);
1050
4e0296a9 1051 saved_rindex = p->rindex;
74b2466e 1052
faa133f3 1053 r = dns_packet_read_key(p, &key, NULL);
74b2466e
LP
1054 if (r < 0)
1055 goto fail;
1056
0e2bcd6a
LP
1057 if (key->class == DNS_CLASS_ANY ||
1058 key->type == DNS_TYPE_ANY) {
1059 r = -EBADMSG;
1060 goto fail;
1061 }
1062
faa133f3
LP
1063 rr = dns_resource_record_new(key);
1064 if (!rr) {
1065 r = -ENOMEM;
1066 goto fail;
1067 }
1068
74b2466e
LP
1069 r = dns_packet_read_uint32(p, &rr->ttl, NULL);
1070 if (r < 0)
1071 goto fail;
1072
1073 r = dns_packet_read_uint16(p, &rdlength, NULL);
1074 if (r < 0)
1075 goto fail;
1076
1077 if (p->rindex + rdlength > p->size) {
1078 r = -EBADMSG;
1079 goto fail;
1080 }
1081
1082 offset = p->rindex;
1083
faa133f3 1084 switch (rr->key->type) {
74b2466e 1085
9c92ce6d
LP
1086 case DNS_TYPE_SRV:
1087 r = dns_packet_read_uint16(p, &rr->srv.priority, NULL);
1088 if (r < 0)
1089 goto fail;
1090 r = dns_packet_read_uint16(p, &rr->srv.weight, NULL);
1091 if (r < 0)
1092 goto fail;
1093 r = dns_packet_read_uint16(p, &rr->srv.port, NULL);
1094 if (r < 0)
1095 goto fail;
151226ab 1096 r = dns_packet_read_name(p, &rr->srv.name, true, NULL);
9c92ce6d
LP
1097 break;
1098
74b2466e
LP
1099 case DNS_TYPE_PTR:
1100 case DNS_TYPE_NS:
1101 case DNS_TYPE_CNAME:
8ac4e9e1 1102 case DNS_TYPE_DNAME:
151226ab 1103 r = dns_packet_read_name(p, &rr->ptr.name, true, NULL);
74b2466e
LP
1104 break;
1105
1106 case DNS_TYPE_HINFO:
1107 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
1108 if (r < 0)
1109 goto fail;
1110
1111 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
1112 break;
1113
9de3e329 1114 case DNS_TYPE_SPF: /* exactly the same as TXT */
2e276efc
ZJS
1115 case DNS_TYPE_TXT: {
1116 char *s;
1117
cbd67a86 1118 while (p->rindex < offset + rdlength) {
2e276efc
ZJS
1119 r = dns_packet_read_string(p, &s, NULL);
1120 if (r < 0)
1121 goto fail;
1122
1123 r = strv_consume(&rr->txt.strings, s);
1124 if (r < 0)
1125 goto fail;
6a6fc3df
LP
1126 }
1127
1128 r = 0;
2e276efc
ZJS
1129 break;
1130 }
1131
74b2466e 1132 case DNS_TYPE_A:
623a4c97 1133 r = dns_packet_read_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
74b2466e
LP
1134 break;
1135
1136 case DNS_TYPE_AAAA:
623a4c97 1137 r = dns_packet_read_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
74b2466e
LP
1138 break;
1139
7e8e0422 1140 case DNS_TYPE_SOA:
151226ab 1141 r = dns_packet_read_name(p, &rr->soa.mname, true, NULL);
7e8e0422
LP
1142 if (r < 0)
1143 goto fail;
1144
151226ab 1145 r = dns_packet_read_name(p, &rr->soa.rname, true, NULL);
7e8e0422
LP
1146 if (r < 0)
1147 goto fail;
1148
1149 r = dns_packet_read_uint32(p, &rr->soa.serial, NULL);
1150 if (r < 0)
1151 goto fail;
1152
1153 r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL);
1154 if (r < 0)
1155 goto fail;
1156
1157 r = dns_packet_read_uint32(p, &rr->soa.retry, NULL);
1158 if (r < 0)
1159 goto fail;
1160
1161 r = dns_packet_read_uint32(p, &rr->soa.expire, NULL);
1162 if (r < 0)
1163 goto fail;
1164
1165 r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL);
1166 break;
1167
623a4c97 1168 case DNS_TYPE_MX:
946c7094
ZJS
1169 r = dns_packet_read_uint16(p, &rr->mx.priority, NULL);
1170 if (r < 0)
1171 goto fail;
1172
151226ab 1173 r = dns_packet_read_name(p, &rr->mx.exchange, true, NULL);
946c7094
ZJS
1174 break;
1175
0dae31d4
ZJS
1176 case DNS_TYPE_LOC: {
1177 uint8_t t;
1178 size_t pos;
1179
1180 r = dns_packet_read_uint8(p, &t, &pos);
1181 if (r < 0)
1182 goto fail;
1183
1184 if (t == 0) {
1185 rr->loc.version = t;
1186
1187 r = dns_packet_read_uint8(p, &rr->loc.size, NULL);
1188 if (r < 0)
1189 goto fail;
1190
afbc4f26
ZJS
1191 if (!loc_size_ok(rr->loc.size)) {
1192 r = -EBADMSG;
1193 goto fail;
1194 }
1195
0dae31d4
ZJS
1196 r = dns_packet_read_uint8(p, &rr->loc.horiz_pre, NULL);
1197 if (r < 0)
1198 goto fail;
1199
afbc4f26
ZJS
1200 if (!loc_size_ok(rr->loc.horiz_pre)) {
1201 r = -EBADMSG;
1202 goto fail;
1203 }
1204
0dae31d4
ZJS
1205 r = dns_packet_read_uint8(p, &rr->loc.vert_pre, NULL);
1206 if (r < 0)
1207 goto fail;
1208
afbc4f26
ZJS
1209 if (!loc_size_ok(rr->loc.vert_pre)) {
1210 r = -EBADMSG;
1211 goto fail;
1212 }
1213
0dae31d4
ZJS
1214 r = dns_packet_read_uint32(p, &rr->loc.latitude, NULL);
1215 if (r < 0)
1216 goto fail;
1217
1218 r = dns_packet_read_uint32(p, &rr->loc.longitude, NULL);
1219 if (r < 0)
1220 goto fail;
1221
1222 r = dns_packet_read_uint32(p, &rr->loc.altitude, NULL);
1223 if (r < 0)
1224 goto fail;
1225
1226 break;
1227 } else {
1228 dns_packet_rewind(p, pos);
1229 rr->unparseable = true;
afbc4f26 1230 goto unparseable;
0dae31d4
ZJS
1231 }
1232 }
1233
623a4c97 1234 case DNS_TYPE_SSHFP:
42cc2eeb
LP
1235 r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL);
1236 if (r < 0)
1237 goto fail;
1238
1239 r = dns_packet_read_uint8(p, &rr->sshfp.fptype, NULL);
1240 if (r < 0)
1241 goto fail;
1242
8db0d2f5
ZJS
1243 r = dns_packet_read_public_key(p, rdlength - 2,
1244 &rr->sshfp.key, &rr->sshfp.key_size,
1245 NULL);
1246 break;
1247
1248 case DNS_TYPE_DNSKEY: {
1249 uint16_t flags;
1250 uint8_t proto;
1251
1252 r = dns_packet_read_uint16(p, &flags, NULL);
42cc2eeb
LP
1253 if (r < 0)
1254 goto fail;
1255
8db0d2f5
ZJS
1256 r = dnskey_parse_flags(rr, flags);
1257 if (r < 0)
1258 goto fail;
1259
1260 r = dns_packet_read_uint8(p, &proto, NULL);
1261 if (r < 0)
1262 goto fail;
1263
1264 /* protocol is required to be always 3 */
1265 if (proto != 3) {
1266 r = -EBADMSG;
42cc2eeb
LP
1267 goto fail;
1268 }
1269
8db0d2f5
ZJS
1270 r = dns_packet_read_uint8(p, &rr->dnskey.algorithm, NULL);
1271 if (r < 0)
1272 goto fail;
1273
1274 r = dns_packet_read_public_key(p, rdlength - 4,
1275 &rr->dnskey.key, &rr->dnskey.key_size,
1276 NULL);
42cc2eeb 1277 break;
8db0d2f5 1278 }
42cc2eeb 1279
151226ab
ZJS
1280 case DNS_TYPE_RRSIG:
1281 r = dns_packet_read_uint16(p, &rr->rrsig.type_covered, NULL);
1282 if (r < 0)
1283 goto fail;
1284
1285 r = dns_packet_read_uint8(p, &rr->rrsig.algorithm, NULL);
1286 if (r < 0)
1287 goto fail;
1288
1289 r = dns_packet_read_uint8(p, &rr->rrsig.labels, NULL);
1290 if (r < 0)
1291 goto fail;
1292
1293 r = dns_packet_read_uint32(p, &rr->rrsig.original_ttl, NULL);
1294 if (r < 0)
1295 goto fail;
1296
1297 r = dns_packet_read_uint32(p, &rr->rrsig.expiration, NULL);
1298 if (r < 0)
1299 goto fail;
1300
1301 r = dns_packet_read_uint32(p, &rr->rrsig.inception, NULL);
1302 if (r < 0)
1303 goto fail;
1304
1305 r = dns_packet_read_uint16(p, &rr->rrsig.key_tag, NULL);
1306 if (r < 0)
1307 goto fail;
1308
1309 r = dns_packet_read_name(p, &rr->rrsig.signer, false, NULL);
1310 if (r < 0)
1311 goto fail;
1312
1313 r = dns_packet_read_public_key(p, offset + rdlength - p->rindex,
1314 &rr->rrsig.signature, &rr->rrsig.signature_size,
1315 NULL);
1316 break;
1317
74b2466e 1318 default:
afbc4f26 1319 unparseable:
74b2466e
LP
1320 r = dns_packet_read(p, rdlength, &d, NULL);
1321 if (r < 0)
1322 goto fail;
1323
1324 rr->generic.data = memdup(d, rdlength);
1325 if (!rr->generic.data) {
1326 r = -ENOMEM;
1327 goto fail;
1328 }
1329
1330 rr->generic.size = rdlength;
1331 break;
1332 }
1333 if (r < 0)
1334 goto fail;
1335 if (p->rindex != offset + rdlength) {
1336 r = -EBADMSG;
1337 goto fail;
1338 }
1339
1340 *ret = rr;
1341 rr = NULL;
1342
1343 if (start)
1344 *start = saved_rindex;
1345
1346 return 0;
1347fail:
1348 dns_packet_rewind(p, saved_rindex);
1349 return r;
1350}
1351
faa133f3
LP
1352int dns_packet_extract(DnsPacket *p) {
1353 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
1354 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
1355 size_t saved_rindex;
1356 unsigned n, i;
74b2466e
LP
1357 int r;
1358
a4076574
LP
1359 if (p->extracted)
1360 return 0;
1361
faa133f3 1362 saved_rindex = p->rindex;
322345fd
LP
1363 dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
1364
3cb10d3a 1365 n = DNS_PACKET_QDCOUNT(p);
faa133f3
LP
1366 if (n > 0) {
1367 question = dns_question_new(n);
1368 if (!question) {
1369 r = -ENOMEM;
1370 goto finish;
1371 }
74b2466e 1372
faa133f3
LP
1373 for (i = 0; i < n; i++) {
1374 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
74b2466e 1375
faa133f3
LP
1376 r = dns_packet_read_key(p, &key, NULL);
1377 if (r < 0)
1378 goto finish;
74b2466e 1379
faa133f3
LP
1380 r = dns_question_add(question, key);
1381 if (r < 0)
1382 goto finish;
1383 }
1384 }
322345fd 1385
faa133f3
LP
1386 n = DNS_PACKET_RRCOUNT(p);
1387 if (n > 0) {
1388 answer = dns_answer_new(n);
1389 if (!answer) {
1390 r = -ENOMEM;
1391 goto finish;
1392 }
322345fd 1393
faa133f3
LP
1394 for (i = 0; i < n; i++) {
1395 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
322345fd 1396
faa133f3
LP
1397 r = dns_packet_read_rr(p, &rr, NULL);
1398 if (r < 0)
1399 goto finish;
322345fd 1400
faa133f3
LP
1401 r = dns_answer_add(answer, rr);
1402 if (r < 0)
1403 goto finish;
1404 }
322345fd
LP
1405 }
1406
faa133f3
LP
1407 p->question = question;
1408 question = NULL;
322345fd 1409
faa133f3
LP
1410 p->answer = answer;
1411 answer = NULL;
322345fd 1412
a4076574
LP
1413 p->extracted = true;
1414
faa133f3 1415 r = 0;
322345fd
LP
1416
1417finish:
1418 p->rindex = saved_rindex;
1419 return r;
1420}
1421
74b2466e
LP
1422static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
1423 [DNS_RCODE_SUCCESS] = "SUCCESS",
1424 [DNS_RCODE_FORMERR] = "FORMERR",
1425 [DNS_RCODE_SERVFAIL] = "SERVFAIL",
1426 [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
1427 [DNS_RCODE_NOTIMP] = "NOTIMP",
1428 [DNS_RCODE_REFUSED] = "REFUSED",
1429 [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
1430 [DNS_RCODE_YXRRSET] = "YRRSET",
1431 [DNS_RCODE_NXRRSET] = "NXRRSET",
1432 [DNS_RCODE_NOTAUTH] = "NOTAUTH",
1433 [DNS_RCODE_NOTZONE] = "NOTZONE",
1434 [DNS_RCODE_BADVERS] = "BADVERS",
1435 [DNS_RCODE_BADKEY] = "BADKEY",
1436 [DNS_RCODE_BADTIME] = "BADTIME",
1437 [DNS_RCODE_BADMODE] = "BADMODE",
1438 [DNS_RCODE_BADNAME] = "BADNAME",
1439 [DNS_RCODE_BADALG] = "BADALG",
1440 [DNS_RCODE_BADTRUNC] = "BADTRUNC",
1441};
1442DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);
1716f6dc
LP
1443
1444static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
1445 [DNS_PROTOCOL_DNS] = "dns",
1446 [DNS_PROTOCOL_MDNS] = "mdns",
1447 [DNS_PROTOCOL_LLMNR] = "llmnr",
1448};
1449DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);
ff3d6560
ZJS
1450
1451static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
1452 [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
1453 [DNSSEC_ALGORITHM_DH] = "DH",
1454 [DNSSEC_ALGORITHM_DSA] = "DSA",
1455 [DNSSEC_ALGORITHM_ECC] = "ECC",
1456 [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
1457 [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
1458 [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
1459 [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
1460};
1461DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int);