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