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