]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-packet.c
util-lib: split stat()/statfs()/stavfs() related calls into stat-util.[ch]
[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"
4ad7f276 26#include "dns-domain.h"
74b2466e
LP
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
a0166609 35 if (mtu <= UDP_PACKET_HEADER_SIZE)
74b2466e
LP
36 a = DNS_PACKET_SIZE_START;
37 else
a0166609 38 a = mtu - UDP_PACKET_HEADER_SIZE;
74b2466e
LP
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;
069360a6 67 int r;
74b2466e
LP
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
069360a6
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 */));
87 else
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
818ef443
DM
169 switch (p->protocol) {
170 case DNS_PROTOCOL_LLMNR:
171 /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */
172 if (DNS_PACKET_QDCOUNT(p) != 1)
173 return -EBADMSG;
174
175 break;
176
177 default:
178 break;
179 }
ea917db9 180
623a4c97
LP
181 return 1;
182}
183
184int dns_packet_validate_query(DnsPacket *p) {
185 int r;
186
187 assert(p);
188
189 r = dns_packet_validate(p);
190 if (r < 0)
191 return r;
192
193 if (DNS_PACKET_QR(p) != 0)
194 return 0;
195
3cb10d3a 196 if (DNS_PACKET_OPCODE(p) != 0)
74b2466e
LP
197 return -EBADMSG;
198
623a4c97
LP
199 if (DNS_PACKET_TC(p))
200 return -EBADMSG;
201
818ef443
DM
202 switch (p->protocol) {
203 case DNS_PROTOCOL_LLMNR:
204 /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */
205 if (DNS_PACKET_QDCOUNT(p) != 1)
206 return -EBADMSG;
623a4c97 207
818ef443
DM
208 /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */
209 if (DNS_PACKET_ANCOUNT(p) > 0)
210 return -EBADMSG;
623a4c97 211
818ef443
DM
212 /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */
213 if (DNS_PACKET_NSCOUNT(p) > 0)
214 return -EBADMSG;
215
216 break;
217
218 default:
219 break;
220 }
623a4c97
LP
221
222 return 1;
74b2466e
LP
223}
224
225static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
226 assert(p);
227
c73ce96b
LP
228 if (p->size + add > p->allocated) {
229 size_t a;
230
231 a = PAGE_ALIGN((p->size + add) * 2);
232 if (a > DNS_PACKET_SIZE_MAX)
233 a = DNS_PACKET_SIZE_MAX;
234
235 if (p->size + add > a)
236 return -EMSGSIZE;
237
faa133f3 238 if (p->_data) {
c73ce96b
LP
239 void *d;
240
faa133f3 241 d = realloc(p->_data, a);
c73ce96b
LP
242 if (!d)
243 return -ENOMEM;
244
faa133f3 245 p->_data = d;
c73ce96b 246 } else {
faa133f3
LP
247 p->_data = malloc(a);
248 if (!p->_data)
c73ce96b
LP
249 return -ENOMEM;
250
faa133f3
LP
251 memcpy(p->_data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size);
252 memzero((uint8_t*) p->_data + p->size, a - p->size);
c73ce96b
LP
253 }
254
255 p->allocated = a;
256 }
74b2466e
LP
257
258 if (start)
259 *start = p->size;
260
261 if (ret)
262 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size;
263
264 p->size += add;
265 return 0;
266}
267
268static void dns_packet_truncate(DnsPacket *p, size_t sz) {
269 Iterator i;
270 char *s;
271 void *n;
272
273 assert(p);
274
275 if (p->size <= sz)
276 return;
277
0e03ade5 278 HASHMAP_FOREACH_KEY(n, s, p->names, i) {
74b2466e
LP
279
280 if (PTR_TO_SIZE(n) < sz)
281 continue;
282
283 hashmap_remove(p->names, s);
284 free(s);
285 }
286
287 p->size = sz;
288}
289
623a4c97
LP
290int dns_packet_append_blob(DnsPacket *p, const void *d, size_t l, size_t *start) {
291 void *q;
292 int r;
293
294 assert(p);
295
296 r = dns_packet_extend(p, l, &q, start);
297 if (r < 0)
298 return r;
299
300 memcpy(q, d, l);
301 return 0;
302}
303
74b2466e
LP
304int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) {
305 void *d;
306 int r;
307
308 assert(p);
309
310 r = dns_packet_extend(p, sizeof(uint8_t), &d, start);
311 if (r < 0)
312 return r;
313
314 ((uint8_t*) d)[0] = v;
315
316 return 0;
317}
318
319int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
320 void *d;
321 int r;
322
323 assert(p);
324
325 r = dns_packet_extend(p, sizeof(uint16_t), &d, start);
326 if (r < 0)
327 return r;
328
725ca0e5 329 unaligned_write_be16(d, v);
623a4c97
LP
330
331 return 0;
332}
333
334int dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start) {
335 void *d;
336 int r;
337
338 assert(p);
339
340 r = dns_packet_extend(p, sizeof(uint32_t), &d, start);
341 if (r < 0)
342 return r;
343
725ca0e5 344 unaligned_write_be32(d, v);
74b2466e
LP
345
346 return 0;
347}
348
349int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
350 void *d;
351 size_t l;
352 int r;
353
354 assert(p);
355 assert(s);
356
357 l = strlen(s);
358 if (l > 255)
359 return -E2BIG;
360
361 r = dns_packet_extend(p, 1 + l, &d, start);
362 if (r < 0)
363 return r;
364
365 ((uint8_t*) d)[0] = (uint8_t) l;
366 memcpy(((uint8_t*) d) + 1, s, l);
367
368 return 0;
369}
370
371int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
372 void *w;
373 int r;
374
375 assert(p);
376 assert(d);
377
378 if (l > DNS_LABEL_MAX)
379 return -E2BIG;
380
381 r = dns_packet_extend(p, 1 + l, &w, start);
382 if (r < 0)
383 return r;
384
385 ((uint8_t*) w)[0] = (uint8_t) l;
386 memcpy(((uint8_t*) w) + 1, d, l);
387
388 return 0;
389}
390
f6a5fec6
LP
391int dns_packet_append_name(
392 DnsPacket *p,
393 const char *name,
394 bool allow_compression,
395 size_t *start) {
396
74b2466e
LP
397 size_t saved_size;
398 int r;
399
400 assert(p);
401 assert(name);
402
f6a5fec6
LP
403 if (p->refuse_compression)
404 allow_compression = false;
405
74b2466e
LP
406 saved_size = p->size;
407
408 while (*name) {
409 _cleanup_free_ char *s = NULL;
410 char label[DNS_LABEL_MAX];
151226ab 411 size_t n = 0;
bdf10b5b 412 int k;
74b2466e 413
151226ab
ZJS
414 if (allow_compression)
415 n = PTR_TO_SIZE(hashmap_get(p->names, name));
74b2466e
LP
416 if (n > 0) {
417 assert(n < p->size);
418
419 if (n < 0x4000) {
420 r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
421 if (r < 0)
422 goto fail;
423
424 goto done;
425 }
426 }
427
428 s = strdup(name);
429 if (!s) {
430 r = -ENOMEM;
431 goto fail;
432 }
433
434 r = dns_label_unescape(&name, label, sizeof(label));
435 if (r < 0)
436 goto fail;
437
bdf10b5b
LP
438 if (p->protocol == DNS_PROTOCOL_DNS)
439 k = dns_label_apply_idna(label, r, label, sizeof(label));
440 else
441 k = dns_label_undo_idna(label, r, label, sizeof(label));
442 if (k < 0) {
443 r = k;
444 goto fail;
445 }
446 if (k > 0)
447 r = k;
448
74b2466e
LP
449 r = dns_packet_append_label(p, label, r, &n);
450 if (r < 0)
451 goto fail;
452
151226ab 453 if (allow_compression) {
d5099efc 454 r = hashmap_ensure_allocated(&p->names, &dns_name_hash_ops);
151226ab
ZJS
455 if (r < 0)
456 goto fail;
74b2466e 457
151226ab
ZJS
458 r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
459 if (r < 0)
460 goto fail;
74b2466e 461
151226ab
ZJS
462 s = NULL;
463 }
74b2466e
LP
464 }
465
466 r = dns_packet_append_uint8(p, 0, NULL);
467 if (r < 0)
468 return r;
469
470done:
471 if (start)
472 *start = saved_size;
473
474 return 0;
475
476fail:
477 dns_packet_truncate(p, saved_size);
478 return r;
479}
480
481int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
482 size_t saved_size;
483 int r;
484
485 assert(p);
486 assert(k);
487
488 saved_size = p->size;
489
151226ab 490 r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, NULL);
74b2466e
LP
491 if (r < 0)
492 goto fail;
493
494 r = dns_packet_append_uint16(p, k->type, NULL);
495 if (r < 0)
496 goto fail;
497
498 r = dns_packet_append_uint16(p, k->class, NULL);
499 if (r < 0)
500 goto fail;
501
502 if (start)
503 *start = saved_size;
504
505 return 0;
506
507fail:
508 dns_packet_truncate(p, saved_size);
509 return r;
510}
511
50f1e641
TG
512static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t length, uint8_t *types, size_t *start) {
513 size_t saved_size;
514 int r;
515
516 assert(p);
517 assert(types);
1792f223 518 assert(length > 0);
50f1e641 519
50f1e641
TG
520 saved_size = p->size;
521
1792f223
TG
522 r = dns_packet_append_uint8(p, window, NULL);
523 if (r < 0)
524 goto fail;
50f1e641 525
1792f223
TG
526 r = dns_packet_append_uint8(p, length, NULL);
527 if (r < 0)
528 goto fail;
6fa91901 529
1792f223
TG
530 r = dns_packet_append_blob(p, types, length, NULL);
531 if (r < 0)
532 goto fail;
50f1e641
TG
533
534 if (start)
535 *start = saved_size;
536
537 return 0;
538fail:
539 dns_packet_truncate(p, saved_size);
540 return r;
541}
542
543static int dns_packet_append_types(DnsPacket *p, Bitmap *types, size_t *start) {
cb57dd41 544 Iterator i;
50f1e641 545 uint8_t window = 0;
1792f223 546 uint8_t entry = 0;
50f1e641
TG
547 uint8_t bitmaps[32] = {};
548 unsigned n;
549 size_t saved_size;
550 int r;
551
552 assert(p);
553 assert(types);
554
555 saved_size = p->size;
556
cb57dd41 557 BITMAP_FOREACH(n, types, i) {
50f1e641
TG
558 assert(n <= 0xffff);
559
1792f223
TG
560 if ((n >> 8) != window && bitmaps[entry / 8] != 0) {
561 r = dns_packet_append_type_window(p, window, entry / 8 + 1, bitmaps, NULL);
50f1e641
TG
562 if (r < 0)
563 goto fail;
564
1792f223 565 zero(bitmaps);
50f1e641
TG
566 }
567
1792f223 568 window = n >> 8;
50f1e641
TG
569
570 entry = n & 255;
571
572 bitmaps[entry / 8] |= 1 << (7 - (entry % 8));
573 }
574
1792f223 575 r = dns_packet_append_type_window(p, window, entry / 8 + 1, bitmaps, NULL);
50f1e641
TG
576 if (r < 0)
577 goto fail;
578
579 if (start)
580 *start = saved_size;
581
582 return 0;
583fail:
584 dns_packet_truncate(p, saved_size);
585 return r;
586}
587
623a4c97
LP
588int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) {
589 size_t saved_size, rdlength_offset, end, rdlength;
590 int r;
591
592 assert(p);
593 assert(rr);
594
595 saved_size = p->size;
596
597 r = dns_packet_append_key(p, rr->key, NULL);
598 if (r < 0)
599 goto fail;
600
601 r = dns_packet_append_uint32(p, rr->ttl, NULL);
602 if (r < 0)
603 goto fail;
604
605 /* Initially we write 0 here */
606 r = dns_packet_append_uint16(p, 0, &rdlength_offset);
607 if (r < 0)
608 goto fail;
609
0dae31d4 610 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
623a4c97 611
9c92ce6d
LP
612 case DNS_TYPE_SRV:
613 r = dns_packet_append_uint16(p, rr->srv.priority, NULL);
614 if (r < 0)
615 goto fail;
616
617 r = dns_packet_append_uint16(p, rr->srv.weight, NULL);
618 if (r < 0)
619 goto fail;
620
621 r = dns_packet_append_uint16(p, rr->srv.port, NULL);
622 if (r < 0)
623 goto fail;
624
151226ab 625 r = dns_packet_append_name(p, rr->srv.name, true, NULL);
9c92ce6d
LP
626 break;
627
623a4c97
LP
628 case DNS_TYPE_PTR:
629 case DNS_TYPE_NS:
630 case DNS_TYPE_CNAME:
8ac4e9e1 631 case DNS_TYPE_DNAME:
151226ab 632 r = dns_packet_append_name(p, rr->ptr.name, true, NULL);
623a4c97
LP
633 break;
634
635 case DNS_TYPE_HINFO:
636 r = dns_packet_append_string(p, rr->hinfo.cpu, NULL);
637 if (r < 0)
638 goto fail;
639
640 r = dns_packet_append_string(p, rr->hinfo.os, NULL);
641 break;
642
9de3e329 643 case DNS_TYPE_SPF: /* exactly the same as TXT */
2e276efc
ZJS
644 case DNS_TYPE_TXT: {
645 char **s;
646
1ccda9b7
LP
647 if (strv_isempty(rr->txt.strings)) {
648 /* RFC 6763, section 6.1 suggests to generate
649 * single empty string for an empty array. */
650
651 r = dns_packet_append_string(p, "", NULL);
2e276efc
ZJS
652 if (r < 0)
653 goto fail;
1ccda9b7
LP
654 } else {
655 STRV_FOREACH(s, rr->txt.strings) {
656 r = dns_packet_append_string(p, *s, NULL);
657 if (r < 0)
658 goto fail;
659 }
2e276efc
ZJS
660 }
661
6a6fc3df 662 r = 0;
2e276efc
ZJS
663 break;
664 }
665
623a4c97
LP
666 case DNS_TYPE_A:
667 r = dns_packet_append_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
668 break;
669
670 case DNS_TYPE_AAAA:
671 r = dns_packet_append_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
672 break;
673
674 case DNS_TYPE_SOA:
151226ab 675 r = dns_packet_append_name(p, rr->soa.mname, true, NULL);
623a4c97
LP
676 if (r < 0)
677 goto fail;
678
151226ab 679 r = dns_packet_append_name(p, rr->soa.rname, true, NULL);
623a4c97
LP
680 if (r < 0)
681 goto fail;
682
683 r = dns_packet_append_uint32(p, rr->soa.serial, NULL);
684 if (r < 0)
685 goto fail;
686
687 r = dns_packet_append_uint32(p, rr->soa.refresh, NULL);
688 if (r < 0)
689 goto fail;
690
691 r = dns_packet_append_uint32(p, rr->soa.retry, NULL);
692 if (r < 0)
693 goto fail;
694
695 r = dns_packet_append_uint32(p, rr->soa.expire, NULL);
696 if (r < 0)
697 goto fail;
698
699 r = dns_packet_append_uint32(p, rr->soa.minimum, NULL);
700 break;
701
702 case DNS_TYPE_MX:
946c7094
ZJS
703 r = dns_packet_append_uint16(p, rr->mx.priority, NULL);
704 if (r < 0)
705 goto fail;
706
151226ab 707 r = dns_packet_append_name(p, rr->mx.exchange, true, NULL);
946c7094
ZJS
708 break;
709
0dae31d4
ZJS
710 case DNS_TYPE_LOC:
711 r = dns_packet_append_uint8(p, rr->loc.version, NULL);
712 if (r < 0)
713 goto fail;
714
715 r = dns_packet_append_uint8(p, rr->loc.size, NULL);
716 if (r < 0)
717 goto fail;
718
719 r = dns_packet_append_uint8(p, rr->loc.horiz_pre, NULL);
720 if (r < 0)
721 goto fail;
722
723 r = dns_packet_append_uint8(p, rr->loc.vert_pre, NULL);
724 if (r < 0)
725 goto fail;
726
afbc4f26 727 r = dns_packet_append_uint32(p, rr->loc.latitude, NULL);
0dae31d4
ZJS
728 if (r < 0)
729 goto fail;
730
afbc4f26 731 r = dns_packet_append_uint32(p, rr->loc.longitude, NULL);
0dae31d4
ZJS
732 if (r < 0)
733 goto fail;
734
afbc4f26 735 r = dns_packet_append_uint32(p, rr->loc.altitude, NULL);
0dae31d4
ZJS
736 break;
737
abf126a3
TG
738 case DNS_TYPE_DS:
739 r = dns_packet_append_uint16(p, rr->ds.key_tag, NULL);
740 if (r < 0)
741 goto fail;
742
743 r = dns_packet_append_uint8(p, rr->ds.algorithm, NULL);
744 if (r < 0)
745 goto fail;
746
747 r = dns_packet_append_uint8(p, rr->ds.digest_type, NULL);
748 if (r < 0)
749 goto fail;
750
751 r = dns_packet_append_blob(p, rr->ds.digest, rr->ds.digest_size, NULL);
752 break;
753
623a4c97 754 case DNS_TYPE_SSHFP:
42cc2eeb
LP
755 r = dns_packet_append_uint8(p, rr->sshfp.algorithm, NULL);
756 if (r < 0)
757 goto fail;
8db0d2f5 758
42cc2eeb
LP
759 r = dns_packet_append_uint8(p, rr->sshfp.fptype, NULL);
760 if (r < 0)
761 goto fail;
762
549c1a25 763 r = dns_packet_append_blob(p, rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, NULL);
42cc2eeb
LP
764 break;
765
8db0d2f5
ZJS
766 case DNS_TYPE_DNSKEY:
767 r = dns_packet_append_uint16(p, dnskey_to_flags(rr), NULL);
768 if (r < 0)
769 goto fail;
770
771 r = dns_packet_append_uint8(p, 3u, NULL);
772 if (r < 0)
773 goto fail;
774
775 r = dns_packet_append_uint8(p, rr->dnskey.algorithm, NULL);
776 if (r < 0)
777 goto fail;
778
779 r = dns_packet_append_blob(p, rr->dnskey.key, rr->dnskey.key_size, NULL);
780 break;
781
151226ab
ZJS
782 case DNS_TYPE_RRSIG:
783 r = dns_packet_append_uint16(p, rr->rrsig.type_covered, NULL);
784 if (r < 0)
785 goto fail;
786
787 r = dns_packet_append_uint8(p, rr->rrsig.algorithm, NULL);
788 if (r < 0)
789 goto fail;
790
791 r = dns_packet_append_uint8(p, rr->rrsig.labels, NULL);
792 if (r < 0)
793 goto fail;
794
795 r = dns_packet_append_uint32(p, rr->rrsig.original_ttl, NULL);
796 if (r < 0)
797 goto fail;
798
799 r = dns_packet_append_uint32(p, rr->rrsig.expiration, NULL);
800 if (r < 0)
801 goto fail;
802
803 r = dns_packet_append_uint32(p, rr->rrsig.inception, NULL);
804 if (r < 0)
805 goto fail;
806
0b1b17d3 807 r = dns_packet_append_uint16(p, rr->rrsig.key_tag, NULL);
151226ab
ZJS
808 if (r < 0)
809 goto fail;
810
811 r = dns_packet_append_name(p, rr->rrsig.signer, false, NULL);
812 if (r < 0)
813 goto fail;
814
815 r = dns_packet_append_blob(p, rr->rrsig.signature, rr->rrsig.signature_size, NULL);
816 break;
817
50f1e641
TG
818 case DNS_TYPE_NSEC:
819 r = dns_packet_append_name(p, rr->nsec.next_domain_name, false, NULL);
820 if (r < 0)
821 goto fail;
822
823 r = dns_packet_append_types(p, rr->nsec.types, NULL);
824 if (r < 0)
825 goto fail;
826
5d45a880
TG
827 break;
828 case DNS_TYPE_NSEC3:
829 r = dns_packet_append_uint8(p, rr->nsec3.algorithm, NULL);
830 if (r < 0)
831 goto fail;
832
833 r = dns_packet_append_uint8(p, rr->nsec3.flags, NULL);
834 if (r < 0)
835 goto fail;
836
837 r = dns_packet_append_uint16(p, rr->nsec3.iterations, NULL);
838 if (r < 0)
839 goto fail;
840
841 r = dns_packet_append_uint8(p, rr->nsec3.salt_size, NULL);
842 if (r < 0)
843 goto fail;
844
845 r = dns_packet_append_blob(p, rr->nsec3.salt, rr->nsec3.salt_size, NULL);
846 if (r < 0)
847 goto fail;
848
849 r = dns_packet_append_uint8(p, rr->nsec3.next_hashed_name_size, NULL);
850 if (r < 0)
851 goto fail;
852
853 r = dns_packet_append_blob(p, rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, NULL);
854 if (r < 0)
855 goto fail;
856
857 r = dns_packet_append_types(p, rr->nsec3.types, NULL);
858 if (r < 0)
859 goto fail;
860
50f1e641 861 break;
0dae31d4 862 case _DNS_TYPE_INVALID: /* unparseable */
623a4c97 863 default:
0dae31d4 864
623a4c97
LP
865 r = dns_packet_append_blob(p, rr->generic.data, rr->generic.size, NULL);
866 break;
867 }
868 if (r < 0)
869 goto fail;
870
871 /* Let's calculate the actual data size and update the field */
872 rdlength = p->size - rdlength_offset - sizeof(uint16_t);
873 if (rdlength > 0xFFFF) {
874 r = ENOSPC;
875 goto fail;
876 }
877
878 end = p->size;
879 p->size = rdlength_offset;
880 r = dns_packet_append_uint16(p, rdlength, NULL);
881 if (r < 0)
882 goto fail;
883 p->size = end;
884
351e6342
LP
885 if (start)
886 *start = saved_size;
887
623a4c97
LP
888 return 0;
889
890fail:
891 dns_packet_truncate(p, saved_size);
892 return r;
893}
894
895
74b2466e
LP
896int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
897 assert(p);
898
899 if (p->rindex + sz > p->size)
900 return -EMSGSIZE;
901
902 if (ret)
903 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
904
905 if (start)
906 *start = p->rindex;
907
908 p->rindex += sz;
909 return 0;
910}
911
8ba9fd9c 912void dns_packet_rewind(DnsPacket *p, size_t idx) {
74b2466e
LP
913 assert(p);
914 assert(idx <= p->size);
915 assert(idx >= DNS_PACKET_HEADER_SIZE);
916
917 p->rindex = idx;
918}
919
623a4c97
LP
920int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start) {
921 const void *q;
922 int r;
923
924 assert(p);
925 assert(d);
926
927 r = dns_packet_read(p, sz, &q, start);
928 if (r < 0)
929 return r;
930
931 memcpy(d, q, sz);
932 return 0;
933}
934
f5430a3e
LP
935static int dns_packet_read_memdup(
936 DnsPacket *p, size_t size,
937 void **ret, size_t *ret_size,
938 size_t *ret_start) {
939
940 const void *src;
941 size_t start;
942 int r;
943
944 assert(p);
945 assert(ret);
946
947 r = dns_packet_read(p, size, &src, &start);
948 if (r < 0)
949 return r;
950
951 if (size <= 0)
952 *ret = NULL;
953 else {
954 void *copy;
955
956 copy = memdup(src, size);
957 if (!copy)
958 return -ENOMEM;
959
960 *ret = copy;
961 }
962
963 if (ret_size)
964 *ret_size = size;
965 if (ret_start)
966 *ret_start = start;
967
968 return 0;
969}
970
74b2466e
LP
971int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
972 const void *d;
973 int r;
974
975 assert(p);
976
977 r = dns_packet_read(p, sizeof(uint8_t), &d, start);
978 if (r < 0)
979 return r;
980
981 *ret = ((uint8_t*) d)[0];
982 return 0;
983}
984
985int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
986 const void *d;
987 int r;
988
989 assert(p);
990
991 r = dns_packet_read(p, sizeof(uint16_t), &d, start);
992 if (r < 0)
993 return r;
994
725ca0e5
TG
995 *ret = unaligned_read_be16(d);
996
74b2466e
LP
997 return 0;
998}
999
1000int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
1001 const void *d;
1002 int r;
1003
1004 assert(p);
1005
1006 r = dns_packet_read(p, sizeof(uint32_t), &d, start);
1007 if (r < 0)
1008 return r;
1009
725ca0e5 1010 *ret = unaligned_read_be32(d);
74b2466e
LP
1011
1012 return 0;
1013}
1014
1015int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
1016 size_t saved_rindex;
1017 const void *d;
1018 char *t;
1019 uint8_t c;
1020 int r;
1021
1022 assert(p);
1023
1024 saved_rindex = p->rindex;
1025
1026 r = dns_packet_read_uint8(p, &c, NULL);
1027 if (r < 0)
1028 goto fail;
1029
1030 r = dns_packet_read(p, c, &d, NULL);
1031 if (r < 0)
1032 goto fail;
1033
1034 if (memchr(d, 0, c)) {
1035 r = -EBADMSG;
1036 goto fail;
1037 }
1038
1039 t = strndup(d, c);
1040 if (!t) {
1041 r = -ENOMEM;
1042 goto fail;
1043 }
1044
1045 if (!utf8_is_valid(t)) {
1046 free(t);
1047 r = -EBADMSG;
1048 goto fail;
1049 }
1050
1051 *ret = t;
1052
1053 if (start)
1054 *start = saved_rindex;
1055
1056 return 0;
1057
1058fail:
1059 dns_packet_rewind(p, saved_rindex);
1060 return r;
1061}
1062
f6a5fec6
LP
1063int dns_packet_read_name(
1064 DnsPacket *p,
1065 char **_ret,
1066 bool allow_compression,
1067 size_t *start) {
1068
c75dbf9b 1069 size_t saved_rindex, after_rindex = 0, jump_barrier;
74b2466e
LP
1070 _cleanup_free_ char *ret = NULL;
1071 size_t n = 0, allocated = 0;
1072 bool first = true;
1073 int r;
1074
1075 assert(p);
1076 assert(_ret);
1077
f6a5fec6
LP
1078 if (p->refuse_compression)
1079 allow_compression = false;
1080
74b2466e 1081 saved_rindex = p->rindex;
c75dbf9b 1082 jump_barrier = p->rindex;
74b2466e
LP
1083
1084 for (;;) {
1085 uint8_t c, d;
1086
1087 r = dns_packet_read_uint8(p, &c, NULL);
1088 if (r < 0)
1089 goto fail;
1090
1091 if (c == 0)
1092 /* End of name */
1093 break;
1094 else if (c <= 63) {
1095 _cleanup_free_ char *t = NULL;
1096 const char *label;
1097
1098 /* Literal label */
1099 r = dns_packet_read(p, c, (const void**) &label, NULL);
1100 if (r < 0)
1101 goto fail;
1102
1103 r = dns_label_escape(label, c, &t);
1104 if (r < 0)
1105 goto fail;
1106
1107 if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
1108 r = -ENOMEM;
1109 goto fail;
1110 }
1111
1112 if (!first)
1113 ret[n++] = '.';
1114 else
1115 first = false;
1116
85818582 1117 memcpy(ret + n, t, r);
74b2466e
LP
1118 n += r;
1119 continue;
151226ab 1120 } else if (allow_compression && (c & 0xc0) == 0xc0) {
74b2466e
LP
1121 uint16_t ptr;
1122
1123 /* Pointer */
1124 r = dns_packet_read_uint8(p, &d, NULL);
1125 if (r < 0)
1126 goto fail;
1127
1128 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
c75dbf9b 1129 if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier) {
74b2466e
LP
1130 r = -EBADMSG;
1131 goto fail;
1132 }
1133
1134 if (after_rindex == 0)
1135 after_rindex = p->rindex;
1136
f131770b 1137 /* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */
c75dbf9b 1138 jump_barrier = ptr;
74b2466e 1139 p->rindex = ptr;
59aa5821
SP
1140 } else {
1141 r = -EBADMSG;
74b2466e 1142 goto fail;
59aa5821 1143 }
74b2466e
LP
1144 }
1145
1146 if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
1147 r = -ENOMEM;
1148 goto fail;
1149 }
1150
1151 ret[n] = 0;
1152
1153 if (after_rindex != 0)
1154 p->rindex= after_rindex;
1155
1156 *_ret = ret;
1157 ret = NULL;
1158
1159 if (start)
1160 *start = saved_rindex;
1161
1162 return 0;
1163
1164fail:
1165 dns_packet_rewind(p, saved_rindex);
1166 return r;
1167}
1168
50f1e641
TG
1169static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *start) {
1170 uint8_t window;
1171 uint8_t length;
1172 const uint8_t *bitmap;
2ad613ad 1173 uint8_t bit = 0;
50f1e641
TG
1174 unsigned i;
1175 bool found = false;
1176 size_t saved_rindex;
1177 int r;
1178
1179 assert(p);
1180 assert(types);
1181
1182 saved_rindex = p->rindex;
1183
1184 r = bitmap_ensure_allocated(types);
1185 if (r < 0)
1186 goto fail;
1187
1188 r = dns_packet_read_uint8(p, &window, NULL);
1189 if (r < 0)
1190 goto fail;
1191
1192 r = dns_packet_read_uint8(p, &length, NULL);
1193 if (r < 0)
1194 goto fail;
1195
1196 if (length == 0 || length > 32)
1197 return -EBADMSG;
1198
1199 r = dns_packet_read(p, length, (const void **)&bitmap, NULL);
1200 if (r < 0)
1201 goto fail;
1202
1203 for (i = 0; i < length; i++) {
1204 uint8_t bitmask = 1 << 7;
50f1e641
TG
1205
1206 if (!bitmap[i]) {
1207 found = false;
2ad613ad 1208 bit += 8;
50f1e641
TG
1209 continue;
1210 }
1211
1212 found = true;
1213
1214 while (bitmask) {
1215 if (bitmap[i] & bitmask) {
1216 uint16_t n;
1217
50f1e641
TG
1218 n = (uint16_t) window << 8 | (uint16_t) bit;
1219
8e6edc49
TG
1220 /* Ignore pseudo-types. see RFC4034 section 4.1.2 */
1221 if (dns_type_is_pseudo(n))
1222 continue;
1223
50f1e641
TG
1224 r = bitmap_set(*types, n);
1225 if (r < 0)
1226 goto fail;
1227 }
1228
1229 bit ++;
1230 bitmask >>= 1;
1231 }
1232 }
1233
1234 if (!found)
1235 return -EBADMSG;
1236
1237 if (start)
1238 *start = saved_rindex;
1239
1240 return 0;
1241fail:
1242 dns_packet_rewind(p, saved_rindex);
1243 return r;
1244}
1245
89492aaf
TG
1246static int dns_packet_read_type_windows(DnsPacket *p, Bitmap **types, size_t size, size_t *start) {
1247 size_t saved_rindex;
1248 int r;
1249
1250 saved_rindex = p->rindex;
1251
1252 while (p->rindex < saved_rindex + size) {
1253 r = dns_packet_read_type_window(p, types, NULL);
1254 if (r < 0)
1255 goto fail;
1256
1257 /* don't read past end of current RR */
1258 if (p->rindex > saved_rindex + size) {
1259 r = -EBADMSG;
1260 goto fail;
1261 }
1262 }
1263
1264 if (p->rindex != saved_rindex + size) {
1265 r = -EBADMSG;
1266 goto fail;
1267 }
1268
1269 if (start)
1270 *start = saved_rindex;
1271
1272 return 0;
1273fail:
1274 dns_packet_rewind(p, saved_rindex);
1275 return r;
1276}
1277
faa133f3
LP
1278int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
1279 _cleanup_free_ char *name = NULL;
1280 uint16_t class, type;
1281 DnsResourceKey *key;
74b2466e
LP
1282 size_t saved_rindex;
1283 int r;
1284
1285 assert(p);
1286 assert(ret);
1287
1288 saved_rindex = p->rindex;
1289
151226ab 1290 r = dns_packet_read_name(p, &name, true, NULL);
74b2466e
LP
1291 if (r < 0)
1292 goto fail;
1293
faa133f3 1294 r = dns_packet_read_uint16(p, &type, NULL);
74b2466e
LP
1295 if (r < 0)
1296 goto fail;
1297
faa133f3 1298 r = dns_packet_read_uint16(p, &class, NULL);
74b2466e
LP
1299 if (r < 0)
1300 goto fail;
1301
faa133f3
LP
1302 key = dns_resource_key_new_consume(class, type, name);
1303 if (!key) {
1304 r = -ENOMEM;
1305 goto fail;
1306 }
1307
1308 name = NULL;
1309 *ret = key;
74b2466e
LP
1310
1311 if (start)
1312 *start = saved_rindex;
1313
1314 return 0;
1315fail:
1316 dns_packet_rewind(p, saved_rindex);
1317 return r;
1318}
1319
afbc4f26
ZJS
1320static bool loc_size_ok(uint8_t size) {
1321 uint8_t m = size >> 4, e = size & 0xF;
1322
1323 return m <= 9 && e <= 9 && (m > 0 || e == 0);
1324}
1325
8db0d2f5 1326static int dnskey_parse_flags(DnsResourceRecord *rr, uint16_t flags) {
3ef77d04
LP
1327 assert(rr);
1328
8db0d2f5
ZJS
1329 if (flags & ~(DNSKEY_FLAG_SEP | DNSKEY_FLAG_ZONE_KEY))
1330 return -EBADMSG;
1331
1332 rr->dnskey.zone_key_flag = flags & DNSKEY_FLAG_ZONE_KEY;
1333 rr->dnskey.sep_flag = flags & DNSKEY_FLAG_SEP;
1334 return 0;
1335}
1336
74b2466e 1337int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
faa133f3
LP
1338 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
1339 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
74b2466e
LP
1340 size_t saved_rindex, offset;
1341 uint16_t rdlength;
74b2466e
LP
1342 int r;
1343
1344 assert(p);
1345 assert(ret);
1346
4e0296a9 1347 saved_rindex = p->rindex;
74b2466e 1348
faa133f3 1349 r = dns_packet_read_key(p, &key, NULL);
74b2466e
LP
1350 if (r < 0)
1351 goto fail;
1352
0e2bcd6a
LP
1353 if (key->class == DNS_CLASS_ANY ||
1354 key->type == DNS_TYPE_ANY) {
1355 r = -EBADMSG;
1356 goto fail;
1357 }
1358
faa133f3
LP
1359 rr = dns_resource_record_new(key);
1360 if (!rr) {
1361 r = -ENOMEM;
1362 goto fail;
1363 }
1364
74b2466e
LP
1365 r = dns_packet_read_uint32(p, &rr->ttl, NULL);
1366 if (r < 0)
1367 goto fail;
1368
1369 r = dns_packet_read_uint16(p, &rdlength, NULL);
1370 if (r < 0)
1371 goto fail;
1372
1373 if (p->rindex + rdlength > p->size) {
1374 r = -EBADMSG;
1375 goto fail;
1376 }
1377
1378 offset = p->rindex;
1379
faa133f3 1380 switch (rr->key->type) {
74b2466e 1381
9c92ce6d
LP
1382 case DNS_TYPE_SRV:
1383 r = dns_packet_read_uint16(p, &rr->srv.priority, NULL);
1384 if (r < 0)
1385 goto fail;
1386 r = dns_packet_read_uint16(p, &rr->srv.weight, NULL);
1387 if (r < 0)
1388 goto fail;
1389 r = dns_packet_read_uint16(p, &rr->srv.port, NULL);
1390 if (r < 0)
1391 goto fail;
151226ab 1392 r = dns_packet_read_name(p, &rr->srv.name, true, NULL);
9c92ce6d
LP
1393 break;
1394
74b2466e
LP
1395 case DNS_TYPE_PTR:
1396 case DNS_TYPE_NS:
1397 case DNS_TYPE_CNAME:
8ac4e9e1 1398 case DNS_TYPE_DNAME:
151226ab 1399 r = dns_packet_read_name(p, &rr->ptr.name, true, NULL);
74b2466e
LP
1400 break;
1401
1402 case DNS_TYPE_HINFO:
1403 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
1404 if (r < 0)
1405 goto fail;
1406
1407 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
1408 break;
1409
9de3e329 1410 case DNS_TYPE_SPF: /* exactly the same as TXT */
1ccda9b7
LP
1411 case DNS_TYPE_TXT:
1412 if (rdlength <= 0) {
1413 /* RFC 6763, section 6.1 suggests to treat
1414 * empty TXT RRs as equivalent to a TXT record
1415 * with a single empty string. */
0e3434ae 1416
1ccda9b7 1417 r = strv_extend(&rr->txt.strings, "");
2e276efc
ZJS
1418 if (r < 0)
1419 goto fail;
1ccda9b7
LP
1420 } else {
1421 while (p->rindex < offset + rdlength) {
1422 char *s;
2e276efc 1423
1ccda9b7
LP
1424 r = dns_packet_read_string(p, &s, NULL);
1425 if (r < 0)
1426 goto fail;
1427
1428 r = strv_consume(&rr->txt.strings, s);
1429 if (r < 0)
1430 goto fail;
1431 }
6a6fc3df
LP
1432 }
1433
1434 r = 0;
2e276efc 1435 break;
2e276efc 1436
74b2466e 1437 case DNS_TYPE_A:
623a4c97 1438 r = dns_packet_read_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
74b2466e
LP
1439 break;
1440
1441 case DNS_TYPE_AAAA:
623a4c97 1442 r = dns_packet_read_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
74b2466e
LP
1443 break;
1444
7e8e0422 1445 case DNS_TYPE_SOA:
151226ab 1446 r = dns_packet_read_name(p, &rr->soa.mname, true, NULL);
7e8e0422
LP
1447 if (r < 0)
1448 goto fail;
1449
151226ab 1450 r = dns_packet_read_name(p, &rr->soa.rname, true, NULL);
7e8e0422
LP
1451 if (r < 0)
1452 goto fail;
1453
1454 r = dns_packet_read_uint32(p, &rr->soa.serial, NULL);
1455 if (r < 0)
1456 goto fail;
1457
1458 r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL);
1459 if (r < 0)
1460 goto fail;
1461
1462 r = dns_packet_read_uint32(p, &rr->soa.retry, NULL);
1463 if (r < 0)
1464 goto fail;
1465
1466 r = dns_packet_read_uint32(p, &rr->soa.expire, NULL);
1467 if (r < 0)
1468 goto fail;
1469
1470 r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL);
1471 break;
1472
623a4c97 1473 case DNS_TYPE_MX:
946c7094
ZJS
1474 r = dns_packet_read_uint16(p, &rr->mx.priority, NULL);
1475 if (r < 0)
1476 goto fail;
1477
151226ab 1478 r = dns_packet_read_name(p, &rr->mx.exchange, true, NULL);
946c7094
ZJS
1479 break;
1480
0dae31d4
ZJS
1481 case DNS_TYPE_LOC: {
1482 uint8_t t;
1483 size_t pos;
1484
1485 r = dns_packet_read_uint8(p, &t, &pos);
1486 if (r < 0)
1487 goto fail;
1488
1489 if (t == 0) {
1490 rr->loc.version = t;
1491
1492 r = dns_packet_read_uint8(p, &rr->loc.size, NULL);
1493 if (r < 0)
1494 goto fail;
1495
afbc4f26
ZJS
1496 if (!loc_size_ok(rr->loc.size)) {
1497 r = -EBADMSG;
1498 goto fail;
1499 }
1500
0dae31d4
ZJS
1501 r = dns_packet_read_uint8(p, &rr->loc.horiz_pre, NULL);
1502 if (r < 0)
1503 goto fail;
1504
afbc4f26
ZJS
1505 if (!loc_size_ok(rr->loc.horiz_pre)) {
1506 r = -EBADMSG;
1507 goto fail;
1508 }
1509
0dae31d4
ZJS
1510 r = dns_packet_read_uint8(p, &rr->loc.vert_pre, NULL);
1511 if (r < 0)
1512 goto fail;
1513
afbc4f26
ZJS
1514 if (!loc_size_ok(rr->loc.vert_pre)) {
1515 r = -EBADMSG;
1516 goto fail;
1517 }
1518
0dae31d4
ZJS
1519 r = dns_packet_read_uint32(p, &rr->loc.latitude, NULL);
1520 if (r < 0)
1521 goto fail;
1522
1523 r = dns_packet_read_uint32(p, &rr->loc.longitude, NULL);
1524 if (r < 0)
1525 goto fail;
1526
1527 r = dns_packet_read_uint32(p, &rr->loc.altitude, NULL);
1528 if (r < 0)
1529 goto fail;
1530
1531 break;
1532 } else {
1533 dns_packet_rewind(p, pos);
1534 rr->unparseable = true;
afbc4f26 1535 goto unparseable;
0dae31d4
ZJS
1536 }
1537 }
1538
abf126a3
TG
1539 case DNS_TYPE_DS:
1540 r = dns_packet_read_uint16(p, &rr->ds.key_tag, NULL);
1541 if (r < 0)
1542 goto fail;
1543
1544 r = dns_packet_read_uint8(p, &rr->ds.algorithm, NULL);
1545 if (r < 0)
1546 goto fail;
1547
1548 r = dns_packet_read_uint8(p, &rr->ds.digest_type, NULL);
1549 if (r < 0)
1550 goto fail;
1551
f5430a3e
LP
1552 r = dns_packet_read_memdup(p, rdlength - 4,
1553 &rr->ds.digest, &rr->ds.digest_size,
1554 NULL);
abf126a3
TG
1555 if (r < 0)
1556 goto fail;
1557
f1d178cc
TG
1558 if (rr->ds.digest_size <= 0) {
1559 /* the accepted size depends on the algorithm, but for now
1560 just ensure that the value is greater than zero */
1561 r = -EBADMSG;
1562 goto fail;
1563 }
1564
abf126a3 1565 break;
623a4c97 1566 case DNS_TYPE_SSHFP:
42cc2eeb
LP
1567 r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL);
1568 if (r < 0)
1569 goto fail;
1570
1571 r = dns_packet_read_uint8(p, &rr->sshfp.fptype, NULL);
1572 if (r < 0)
1573 goto fail;
1574
f5430a3e 1575 r = dns_packet_read_memdup(p, rdlength - 2,
549c1a25 1576 &rr->sshfp.fingerprint, &rr->sshfp.fingerprint_size,
f5430a3e 1577 NULL);
f1d178cc 1578
549c1a25 1579 if (rr->sshfp.fingerprint_size <= 0) {
f1d178cc
TG
1580 /* the accepted size depends on the algorithm, but for now
1581 just ensure that the value is greater than zero */
1582 r = -EBADMSG;
1583 goto fail;
1584 }
1585
8db0d2f5
ZJS
1586 break;
1587
1588 case DNS_TYPE_DNSKEY: {
1589 uint16_t flags;
1590 uint8_t proto;
1591
1592 r = dns_packet_read_uint16(p, &flags, NULL);
42cc2eeb
LP
1593 if (r < 0)
1594 goto fail;
1595
8db0d2f5
ZJS
1596 r = dnskey_parse_flags(rr, flags);
1597 if (r < 0)
1598 goto fail;
1599
1600 r = dns_packet_read_uint8(p, &proto, NULL);
1601 if (r < 0)
1602 goto fail;
1603
1604 /* protocol is required to be always 3 */
1605 if (proto != 3) {
1606 r = -EBADMSG;
42cc2eeb
LP
1607 goto fail;
1608 }
1609
8db0d2f5
ZJS
1610 r = dns_packet_read_uint8(p, &rr->dnskey.algorithm, NULL);
1611 if (r < 0)
1612 goto fail;
1613
f5430a3e
LP
1614 r = dns_packet_read_memdup(p, rdlength - 4,
1615 &rr->dnskey.key, &rr->dnskey.key_size,
1616 NULL);
f1d178cc
TG
1617
1618 if (rr->dnskey.key_size <= 0) {
1619 /* the accepted size depends on the algorithm, but for now
1620 just ensure that the value is greater than zero */
1621 r = -EBADMSG;
1622 goto fail;
1623 }
1624
42cc2eeb 1625 break;
8db0d2f5 1626 }
42cc2eeb 1627
151226ab
ZJS
1628 case DNS_TYPE_RRSIG:
1629 r = dns_packet_read_uint16(p, &rr->rrsig.type_covered, NULL);
1630 if (r < 0)
1631 goto fail;
1632
1633 r = dns_packet_read_uint8(p, &rr->rrsig.algorithm, NULL);
1634 if (r < 0)
1635 goto fail;
1636
1637 r = dns_packet_read_uint8(p, &rr->rrsig.labels, NULL);
1638 if (r < 0)
1639 goto fail;
1640
1641 r = dns_packet_read_uint32(p, &rr->rrsig.original_ttl, NULL);
1642 if (r < 0)
1643 goto fail;
1644
1645 r = dns_packet_read_uint32(p, &rr->rrsig.expiration, NULL);
1646 if (r < 0)
1647 goto fail;
1648
1649 r = dns_packet_read_uint32(p, &rr->rrsig.inception, NULL);
1650 if (r < 0)
1651 goto fail;
1652
1653 r = dns_packet_read_uint16(p, &rr->rrsig.key_tag, NULL);
1654 if (r < 0)
1655 goto fail;
1656
1657 r = dns_packet_read_name(p, &rr->rrsig.signer, false, NULL);
1658 if (r < 0)
1659 goto fail;
1660
f5430a3e
LP
1661 r = dns_packet_read_memdup(p, offset + rdlength - p->rindex,
1662 &rr->rrsig.signature, &rr->rrsig.signature_size,
1663 NULL);
f1d178cc
TG
1664
1665 if (rr->rrsig.signature_size <= 0) {
1666 /* the accepted size depends on the algorithm, but for now
1667 just ensure that the value is greater than zero */
1668 r = -EBADMSG;
1669 goto fail;
1670 }
1671
151226ab
ZJS
1672 break;
1673
50f1e641
TG
1674 case DNS_TYPE_NSEC:
1675 r = dns_packet_read_name(p, &rr->nsec.next_domain_name, false, NULL);
1676 if (r < 0)
1677 goto fail;
1678
89492aaf
TG
1679 r = dns_packet_read_type_windows(p, &rr->nsec.types, offset + rdlength - p->rindex, NULL);
1680 if (r < 0)
1681 goto fail;
1682
bfcc6709
TG
1683 /* The types bitmap must contain at least the NSEC record itself, so an empty bitmap means
1684 something went wrong */
1685 if (bitmap_isclear(rr->nsec.types)) {
1686 r = -EBADMSG;
1687 goto fail;
1688 }
50f1e641
TG
1689
1690 break;
5d45a880
TG
1691
1692 case DNS_TYPE_NSEC3: {
1693 uint8_t size;
1694
1695 r = dns_packet_read_uint8(p, &rr->nsec3.algorithm, NULL);
1696 if (r < 0)
1697 goto fail;
1698
1699 r = dns_packet_read_uint8(p, &rr->nsec3.flags, NULL);
1700 if (r < 0)
1701 goto fail;
1702
1703 r = dns_packet_read_uint16(p, &rr->nsec3.iterations, NULL);
1704 if (r < 0)
1705 goto fail;
1706
f1d178cc 1707 /* this may be zero */
5d45a880
TG
1708 r = dns_packet_read_uint8(p, &size, NULL);
1709 if (r < 0)
1710 goto fail;
1711
f5430a3e 1712 r = dns_packet_read_memdup(p, size, &rr->nsec3.salt, &rr->nsec3.salt_size, NULL);
5d45a880
TG
1713 if (r < 0)
1714 goto fail;
1715
5d45a880
TG
1716 r = dns_packet_read_uint8(p, &size, NULL);
1717 if (r < 0)
1718 goto fail;
1719
f1d178cc
TG
1720 if (size <= 0) {
1721 r = -EBADMSG;
1722 goto fail;
1723 }
1724
f5430a3e 1725 r = dns_packet_read_memdup(p, size, &rr->nsec3.next_hashed_name, &rr->nsec3.next_hashed_name_size, NULL);
5d45a880
TG
1726 if (r < 0)
1727 goto fail;
1728
6b9308d1 1729 r = dns_packet_read_type_windows(p, &rr->nsec3.types, offset + rdlength - p->rindex, NULL);
5d45a880
TG
1730 if (r < 0)
1731 goto fail;
1732
0bbd72b2
TG
1733 /* empty non-terminals can have NSEC3 records, so empty bitmaps are allowed */
1734
5d45a880
TG
1735 break;
1736 }
74b2466e 1737 default:
afbc4f26 1738 unparseable:
f5430a3e 1739 r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.size, NULL);
74b2466e
LP
1740 if (r < 0)
1741 goto fail;
74b2466e
LP
1742 break;
1743 }
1744 if (r < 0)
1745 goto fail;
1746 if (p->rindex != offset + rdlength) {
1747 r = -EBADMSG;
1748 goto fail;
1749 }
1750
1751 *ret = rr;
1752 rr = NULL;
1753
1754 if (start)
1755 *start = saved_rindex;
1756
1757 return 0;
1758fail:
1759 dns_packet_rewind(p, saved_rindex);
1760 return r;
1761}
1762
faa133f3
LP
1763int dns_packet_extract(DnsPacket *p) {
1764 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
1765 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
1766 size_t saved_rindex;
1767 unsigned n, i;
74b2466e
LP
1768 int r;
1769
a4076574
LP
1770 if (p->extracted)
1771 return 0;
1772
faa133f3 1773 saved_rindex = p->rindex;
322345fd
LP
1774 dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
1775
3cb10d3a 1776 n = DNS_PACKET_QDCOUNT(p);
faa133f3
LP
1777 if (n > 0) {
1778 question = dns_question_new(n);
1779 if (!question) {
1780 r = -ENOMEM;
1781 goto finish;
1782 }
74b2466e 1783
faa133f3
LP
1784 for (i = 0; i < n; i++) {
1785 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
74b2466e 1786
faa133f3
LP
1787 r = dns_packet_read_key(p, &key, NULL);
1788 if (r < 0)
1789 goto finish;
74b2466e 1790
faa133f3
LP
1791 r = dns_question_add(question, key);
1792 if (r < 0)
1793 goto finish;
1794 }
1795 }
322345fd 1796
faa133f3
LP
1797 n = DNS_PACKET_RRCOUNT(p);
1798 if (n > 0) {
1799 answer = dns_answer_new(n);
1800 if (!answer) {
1801 r = -ENOMEM;
1802 goto finish;
1803 }
322345fd 1804
faa133f3
LP
1805 for (i = 0; i < n; i++) {
1806 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
322345fd 1807
faa133f3
LP
1808 r = dns_packet_read_rr(p, &rr, NULL);
1809 if (r < 0)
1810 goto finish;
322345fd 1811
78c6a153 1812 r = dns_answer_add(answer, rr, p->ifindex);
faa133f3
LP
1813 if (r < 0)
1814 goto finish;
1815 }
322345fd
LP
1816 }
1817
faa133f3
LP
1818 p->question = question;
1819 question = NULL;
322345fd 1820
faa133f3
LP
1821 p->answer = answer;
1822 answer = NULL;
322345fd 1823
a4076574
LP
1824 p->extracted = true;
1825
faa133f3 1826 r = 0;
322345fd
LP
1827
1828finish:
1829 p->rindex = saved_rindex;
1830 return r;
1831}
1832
74b2466e
LP
1833static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
1834 [DNS_RCODE_SUCCESS] = "SUCCESS",
1835 [DNS_RCODE_FORMERR] = "FORMERR",
1836 [DNS_RCODE_SERVFAIL] = "SERVFAIL",
1837 [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
1838 [DNS_RCODE_NOTIMP] = "NOTIMP",
1839 [DNS_RCODE_REFUSED] = "REFUSED",
1840 [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
1841 [DNS_RCODE_YXRRSET] = "YRRSET",
1842 [DNS_RCODE_NXRRSET] = "NXRRSET",
1843 [DNS_RCODE_NOTAUTH] = "NOTAUTH",
1844 [DNS_RCODE_NOTZONE] = "NOTZONE",
1845 [DNS_RCODE_BADVERS] = "BADVERS",
1846 [DNS_RCODE_BADKEY] = "BADKEY",
1847 [DNS_RCODE_BADTIME] = "BADTIME",
1848 [DNS_RCODE_BADMODE] = "BADMODE",
1849 [DNS_RCODE_BADNAME] = "BADNAME",
1850 [DNS_RCODE_BADALG] = "BADALG",
1851 [DNS_RCODE_BADTRUNC] = "BADTRUNC",
1852};
1853DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);
1716f6dc
LP
1854
1855static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
1856 [DNS_PROTOCOL_DNS] = "dns",
1857 [DNS_PROTOCOL_MDNS] = "mdns",
1858 [DNS_PROTOCOL_LLMNR] = "llmnr",
1859};
1860DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);
ff3d6560
ZJS
1861
1862static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
5d45a880
TG
1863 [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
1864 [DNSSEC_ALGORITHM_DH] = "DH",
1865 [DNSSEC_ALGORITHM_DSA] = "DSA",
1866 [DNSSEC_ALGORITHM_ECC] = "ECC",
1867 [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
1868 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1",
1869 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1",
1870 [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
1871 [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
1872 [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
ff3d6560
ZJS
1873};
1874DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int);