]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-packet.c
resolved: properly process DNAME RRs
[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;
393
394 n = PTR_TO_SIZE(hashmap_get(p->names, name));
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
417 r = dns_packet_append_label(p, label, r, &n);
418 if (r < 0)
419 goto fail;
420
421 r = hashmap_ensure_allocated(&p->names, dns_name_hash_func, dns_name_compare_func);
422 if (r < 0)
423 goto fail;
424
425 r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
426 if (r < 0)
427 goto fail;
428
429 s = NULL;
430 }
431
432 r = dns_packet_append_uint8(p, 0, NULL);
433 if (r < 0)
434 return r;
435
436done:
437 if (start)
438 *start = saved_size;
439
440 return 0;
441
442fail:
443 dns_packet_truncate(p, saved_size);
444 return r;
445}
446
447int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
448 size_t saved_size;
449 int r;
450
451 assert(p);
452 assert(k);
453
454 saved_size = p->size;
455
faa133f3 456 r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), NULL);
74b2466e
LP
457 if (r < 0)
458 goto fail;
459
460 r = dns_packet_append_uint16(p, k->type, NULL);
461 if (r < 0)
462 goto fail;
463
464 r = dns_packet_append_uint16(p, k->class, NULL);
465 if (r < 0)
466 goto fail;
467
468 if (start)
469 *start = saved_size;
470
471 return 0;
472
473fail:
474 dns_packet_truncate(p, saved_size);
475 return r;
476}
477
623a4c97
LP
478int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) {
479 size_t saved_size, rdlength_offset, end, rdlength;
480 int r;
481
482 assert(p);
483 assert(rr);
484
485 saved_size = p->size;
486
487 r = dns_packet_append_key(p, rr->key, NULL);
488 if (r < 0)
489 goto fail;
490
491 r = dns_packet_append_uint32(p, rr->ttl, NULL);
492 if (r < 0)
493 goto fail;
494
495 /* Initially we write 0 here */
496 r = dns_packet_append_uint16(p, 0, &rdlength_offset);
497 if (r < 0)
498 goto fail;
499
0dae31d4 500 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
623a4c97
LP
501
502 case DNS_TYPE_PTR:
503 case DNS_TYPE_NS:
504 case DNS_TYPE_CNAME:
8ac4e9e1 505 case DNS_TYPE_DNAME:
623a4c97
LP
506 r = dns_packet_append_name(p, rr->ptr.name, NULL);
507 break;
508
509 case DNS_TYPE_HINFO:
510 r = dns_packet_append_string(p, rr->hinfo.cpu, NULL);
511 if (r < 0)
512 goto fail;
513
514 r = dns_packet_append_string(p, rr->hinfo.os, NULL);
515 break;
516
9de3e329 517 case DNS_TYPE_SPF: /* exactly the same as TXT */
2e276efc
ZJS
518 case DNS_TYPE_TXT: {
519 char **s;
520
521 STRV_FOREACH(s, rr->txt.strings) {
522 r = dns_packet_append_string(p, *s, NULL);
523 if (r < 0)
524 goto fail;
525 }
526
527 break;
528 }
529
623a4c97
LP
530 case DNS_TYPE_A:
531 r = dns_packet_append_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
532 break;
533
534 case DNS_TYPE_AAAA:
535 r = dns_packet_append_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
536 break;
537
538 case DNS_TYPE_SOA:
539 r = dns_packet_append_name(p, rr->soa.mname, NULL);
540 if (r < 0)
541 goto fail;
542
543 r = dns_packet_append_name(p, rr->soa.rname, NULL);
544 if (r < 0)
545 goto fail;
546
547 r = dns_packet_append_uint32(p, rr->soa.serial, NULL);
548 if (r < 0)
549 goto fail;
550
551 r = dns_packet_append_uint32(p, rr->soa.refresh, NULL);
552 if (r < 0)
553 goto fail;
554
555 r = dns_packet_append_uint32(p, rr->soa.retry, NULL);
556 if (r < 0)
557 goto fail;
558
559 r = dns_packet_append_uint32(p, rr->soa.expire, NULL);
560 if (r < 0)
561 goto fail;
562
563 r = dns_packet_append_uint32(p, rr->soa.minimum, NULL);
564 break;
565
566 case DNS_TYPE_MX:
946c7094
ZJS
567 r = dns_packet_append_uint16(p, rr->mx.priority, NULL);
568 if (r < 0)
569 goto fail;
570
571 r = dns_packet_append_name(p, rr->mx.exchange, NULL);
572 break;
573
0dae31d4
ZJS
574 case DNS_TYPE_LOC:
575 r = dns_packet_append_uint8(p, rr->loc.version, NULL);
576 if (r < 0)
577 goto fail;
578
579 r = dns_packet_append_uint8(p, rr->loc.size, NULL);
580 if (r < 0)
581 goto fail;
582
583 r = dns_packet_append_uint8(p, rr->loc.horiz_pre, NULL);
584 if (r < 0)
585 goto fail;
586
587 r = dns_packet_append_uint8(p, rr->loc.vert_pre, NULL);
588 if (r < 0)
589 goto fail;
590
591 r = dns_packet_append_uint16(p, rr->loc.latitude, NULL);
592 if (r < 0)
593 goto fail;
594
595 r = dns_packet_append_uint16(p, rr->loc.longitude, NULL);
596 if (r < 0)
597 goto fail;
598
599 r = dns_packet_append_uint16(p, rr->loc.altitude, NULL);
600 break;
601
623a4c97 602 case DNS_TYPE_SRV:
623a4c97 603 case DNS_TYPE_SSHFP:
0dae31d4 604 case _DNS_TYPE_INVALID: /* unparseable */
623a4c97 605 default:
0dae31d4 606
623a4c97
LP
607 r = dns_packet_append_blob(p, rr->generic.data, rr->generic.size, NULL);
608 break;
609 }
610 if (r < 0)
611 goto fail;
612
613 /* Let's calculate the actual data size and update the field */
614 rdlength = p->size - rdlength_offset - sizeof(uint16_t);
615 if (rdlength > 0xFFFF) {
616 r = ENOSPC;
617 goto fail;
618 }
619
620 end = p->size;
621 p->size = rdlength_offset;
622 r = dns_packet_append_uint16(p, rdlength, NULL);
623 if (r < 0)
624 goto fail;
625 p->size = end;
626
351e6342
LP
627 if (start)
628 *start = saved_size;
629
623a4c97
LP
630 return 0;
631
632fail:
633 dns_packet_truncate(p, saved_size);
634 return r;
635}
636
637
74b2466e
LP
638int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
639 assert(p);
640
641 if (p->rindex + sz > p->size)
642 return -EMSGSIZE;
643
644 if (ret)
645 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
646
647 if (start)
648 *start = p->rindex;
649
650 p->rindex += sz;
651 return 0;
652}
653
8ba9fd9c 654void dns_packet_rewind(DnsPacket *p, size_t idx) {
74b2466e
LP
655 assert(p);
656 assert(idx <= p->size);
657 assert(idx >= DNS_PACKET_HEADER_SIZE);
658
659 p->rindex = idx;
660}
661
623a4c97
LP
662int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start) {
663 const void *q;
664 int r;
665
666 assert(p);
667 assert(d);
668
669 r = dns_packet_read(p, sz, &q, start);
670 if (r < 0)
671 return r;
672
673 memcpy(d, q, sz);
674 return 0;
675}
676
74b2466e
LP
677int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
678 const void *d;
679 int r;
680
681 assert(p);
682
683 r = dns_packet_read(p, sizeof(uint8_t), &d, start);
684 if (r < 0)
685 return r;
686
687 *ret = ((uint8_t*) d)[0];
688 return 0;
689}
690
691int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
692 const void *d;
693 int r;
694
695 assert(p);
696
697 r = dns_packet_read(p, sizeof(uint16_t), &d, start);
698 if (r < 0)
699 return r;
700
701 *ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) |
702 ((uint16_t) ((uint8_t*) d)[1]);
703 return 0;
704}
705
706int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
707 const void *d;
708 int r;
709
710 assert(p);
711
712 r = dns_packet_read(p, sizeof(uint32_t), &d, start);
713 if (r < 0)
714 return r;
715
716 *ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) |
717 (((uint32_t) ((uint8_t*) d)[1]) << 16) |
718 (((uint32_t) ((uint8_t*) d)[2]) << 8) |
719 ((uint32_t) ((uint8_t*) d)[3]);
720
721 return 0;
722}
723
724int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
725 size_t saved_rindex;
726 const void *d;
727 char *t;
728 uint8_t c;
729 int r;
730
731 assert(p);
732
733 saved_rindex = p->rindex;
734
735 r = dns_packet_read_uint8(p, &c, NULL);
736 if (r < 0)
737 goto fail;
738
739 r = dns_packet_read(p, c, &d, NULL);
740 if (r < 0)
741 goto fail;
742
743 if (memchr(d, 0, c)) {
744 r = -EBADMSG;
745 goto fail;
746 }
747
748 t = strndup(d, c);
749 if (!t) {
750 r = -ENOMEM;
751 goto fail;
752 }
753
754 if (!utf8_is_valid(t)) {
755 free(t);
756 r = -EBADMSG;
757 goto fail;
758 }
759
760 *ret = t;
761
762 if (start)
763 *start = saved_rindex;
764
765 return 0;
766
767fail:
768 dns_packet_rewind(p, saved_rindex);
769 return r;
770}
771
772int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
773 size_t saved_rindex, after_rindex = 0;
774 _cleanup_free_ char *ret = NULL;
775 size_t n = 0, allocated = 0;
776 bool first = true;
777 int r;
778
779 assert(p);
780 assert(_ret);
781
782 saved_rindex = p->rindex;
783
784 for (;;) {
785 uint8_t c, d;
786
787 r = dns_packet_read_uint8(p, &c, NULL);
788 if (r < 0)
789 goto fail;
790
791 if (c == 0)
792 /* End of name */
793 break;
794 else if (c <= 63) {
795 _cleanup_free_ char *t = NULL;
796 const char *label;
797
798 /* Literal label */
799 r = dns_packet_read(p, c, (const void**) &label, NULL);
800 if (r < 0)
801 goto fail;
802
803 r = dns_label_escape(label, c, &t);
804 if (r < 0)
805 goto fail;
806
807 if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
808 r = -ENOMEM;
809 goto fail;
810 }
811
812 if (!first)
813 ret[n++] = '.';
814 else
815 first = false;
816
817 memcpy(ret + n, t, c);
818 n += r;
819 continue;
820 } else if ((c & 0xc0) == 0xc0) {
821 uint16_t ptr;
822
823 /* Pointer */
824 r = dns_packet_read_uint8(p, &d, NULL);
825 if (r < 0)
826 goto fail;
827
828 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
829 if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) {
830 r = -EBADMSG;
831 goto fail;
832 }
833
834 if (after_rindex == 0)
835 after_rindex = p->rindex;
836
837 p->rindex = ptr;
838 } else
839 goto fail;
840 }
841
842 if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
843 r = -ENOMEM;
844 goto fail;
845 }
846
847 ret[n] = 0;
848
849 if (after_rindex != 0)
850 p->rindex= after_rindex;
851
852 *_ret = ret;
853 ret = NULL;
854
855 if (start)
856 *start = saved_rindex;
857
858 return 0;
859
860fail:
861 dns_packet_rewind(p, saved_rindex);
862 return r;
863}
864
faa133f3
LP
865int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
866 _cleanup_free_ char *name = NULL;
867 uint16_t class, type;
868 DnsResourceKey *key;
74b2466e
LP
869 size_t saved_rindex;
870 int r;
871
872 assert(p);
873 assert(ret);
874
875 saved_rindex = p->rindex;
876
faa133f3 877 r = dns_packet_read_name(p, &name, NULL);
74b2466e
LP
878 if (r < 0)
879 goto fail;
880
faa133f3 881 r = dns_packet_read_uint16(p, &type, NULL);
74b2466e
LP
882 if (r < 0)
883 goto fail;
884
faa133f3 885 r = dns_packet_read_uint16(p, &class, NULL);
74b2466e
LP
886 if (r < 0)
887 goto fail;
888
faa133f3
LP
889 key = dns_resource_key_new_consume(class, type, name);
890 if (!key) {
891 r = -ENOMEM;
892 goto fail;
893 }
894
895 name = NULL;
896 *ret = key;
74b2466e
LP
897
898 if (start)
899 *start = saved_rindex;
900
901 return 0;
902fail:
903 dns_packet_rewind(p, saved_rindex);
904 return r;
905}
906
907int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
faa133f3
LP
908 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
909 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
74b2466e
LP
910 size_t saved_rindex, offset;
911 uint16_t rdlength;
912 const void *d;
913 int r;
914
915 assert(p);
916 assert(ret);
917
4e0296a9 918 saved_rindex = p->rindex;
74b2466e 919
faa133f3 920 r = dns_packet_read_key(p, &key, NULL);
74b2466e
LP
921 if (r < 0)
922 goto fail;
923
0e2bcd6a
LP
924 if (key->class == DNS_CLASS_ANY ||
925 key->type == DNS_TYPE_ANY) {
926 r = -EBADMSG;
927 goto fail;
928 }
929
faa133f3
LP
930 rr = dns_resource_record_new(key);
931 if (!rr) {
932 r = -ENOMEM;
933 goto fail;
934 }
935
74b2466e
LP
936 r = dns_packet_read_uint32(p, &rr->ttl, NULL);
937 if (r < 0)
938 goto fail;
939
940 r = dns_packet_read_uint16(p, &rdlength, NULL);
941 if (r < 0)
942 goto fail;
943
944 if (p->rindex + rdlength > p->size) {
945 r = -EBADMSG;
946 goto fail;
947 }
948
949 offset = p->rindex;
950
faa133f3 951 switch (rr->key->type) {
74b2466e
LP
952
953 case DNS_TYPE_PTR:
954 case DNS_TYPE_NS:
955 case DNS_TYPE_CNAME:
8ac4e9e1 956 case DNS_TYPE_DNAME:
74b2466e
LP
957 r = dns_packet_read_name(p, &rr->ptr.name, NULL);
958 break;
959
960 case DNS_TYPE_HINFO:
961 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
962 if (r < 0)
963 goto fail;
964
965 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
966 break;
967
9de3e329 968 case DNS_TYPE_SPF: /* exactly the same as TXT */
2e276efc
ZJS
969 case DNS_TYPE_TXT: {
970 char *s;
971
cbd67a86 972 while (p->rindex < offset + rdlength) {
2e276efc
ZJS
973 r = dns_packet_read_string(p, &s, NULL);
974 if (r < 0)
975 goto fail;
976
977 r = strv_consume(&rr->txt.strings, s);
978 if (r < 0)
979 goto fail;
980 };
981 break;
982 }
983
74b2466e 984 case DNS_TYPE_A:
623a4c97 985 r = dns_packet_read_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
74b2466e
LP
986 break;
987
988 case DNS_TYPE_AAAA:
623a4c97 989 r = dns_packet_read_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
74b2466e
LP
990 break;
991
7e8e0422
LP
992 case DNS_TYPE_SOA:
993 r = dns_packet_read_name(p, &rr->soa.mname, NULL);
994 if (r < 0)
995 goto fail;
996
997 r = dns_packet_read_name(p, &rr->soa.rname, NULL);
998 if (r < 0)
999 goto fail;
1000
1001 r = dns_packet_read_uint32(p, &rr->soa.serial, NULL);
1002 if (r < 0)
1003 goto fail;
1004
1005 r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL);
1006 if (r < 0)
1007 goto fail;
1008
1009 r = dns_packet_read_uint32(p, &rr->soa.retry, NULL);
1010 if (r < 0)
1011 goto fail;
1012
1013 r = dns_packet_read_uint32(p, &rr->soa.expire, NULL);
1014 if (r < 0)
1015 goto fail;
1016
1017 r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL);
1018 break;
1019
623a4c97 1020 case DNS_TYPE_MX:
946c7094
ZJS
1021 r = dns_packet_read_uint16(p, &rr->mx.priority, NULL);
1022 if (r < 0)
1023 goto fail;
1024
1025 r = dns_packet_read_name(p, &rr->mx.exchange, NULL);
1026 break;
1027
0dae31d4
ZJS
1028 case DNS_TYPE_LOC: {
1029 uint8_t t;
1030 size_t pos;
1031
1032 r = dns_packet_read_uint8(p, &t, &pos);
1033 if (r < 0)
1034 goto fail;
1035
1036 if (t == 0) {
1037 rr->loc.version = t;
1038
1039 r = dns_packet_read_uint8(p, &rr->loc.size, NULL);
1040 if (r < 0)
1041 goto fail;
1042
1043 r = dns_packet_read_uint8(p, &rr->loc.horiz_pre, NULL);
1044 if (r < 0)
1045 goto fail;
1046
1047 r = dns_packet_read_uint8(p, &rr->loc.vert_pre, NULL);
1048 if (r < 0)
1049 goto fail;
1050
1051 r = dns_packet_read_uint32(p, &rr->loc.latitude, NULL);
1052 if (r < 0)
1053 goto fail;
1054
1055 r = dns_packet_read_uint32(p, &rr->loc.longitude, NULL);
1056 if (r < 0)
1057 goto fail;
1058
1059 r = dns_packet_read_uint32(p, &rr->loc.altitude, NULL);
1060 if (r < 0)
1061 goto fail;
1062
1063 break;
1064 } else {
1065 dns_packet_rewind(p, pos);
1066 rr->unparseable = true;
1067 /* fall through */
1068 }
1069 }
1070
623a4c97 1071 case DNS_TYPE_SRV:
623a4c97 1072 case DNS_TYPE_SSHFP:
74b2466e
LP
1073 default:
1074 r = dns_packet_read(p, rdlength, &d, NULL);
1075 if (r < 0)
1076 goto fail;
1077
1078 rr->generic.data = memdup(d, rdlength);
1079 if (!rr->generic.data) {
1080 r = -ENOMEM;
1081 goto fail;
1082 }
1083
1084 rr->generic.size = rdlength;
1085 break;
1086 }
1087 if (r < 0)
1088 goto fail;
1089 if (p->rindex != offset + rdlength) {
1090 r = -EBADMSG;
1091 goto fail;
1092 }
1093
1094 *ret = rr;
1095 rr = NULL;
1096
1097 if (start)
1098 *start = saved_rindex;
1099
1100 return 0;
1101fail:
1102 dns_packet_rewind(p, saved_rindex);
1103 return r;
1104}
1105
faa133f3
LP
1106int dns_packet_extract(DnsPacket *p) {
1107 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
1108 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
1109 size_t saved_rindex;
1110 unsigned n, i;
74b2466e
LP
1111 int r;
1112
faa133f3 1113 saved_rindex = p->rindex;
322345fd
LP
1114 dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
1115
3cb10d3a 1116 n = DNS_PACKET_QDCOUNT(p);
faa133f3
LP
1117 if (n > 0) {
1118 question = dns_question_new(n);
1119 if (!question) {
1120 r = -ENOMEM;
1121 goto finish;
1122 }
74b2466e 1123
faa133f3
LP
1124 for (i = 0; i < n; i++) {
1125 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
74b2466e 1126
faa133f3
LP
1127 r = dns_packet_read_key(p, &key, NULL);
1128 if (r < 0)
1129 goto finish;
74b2466e 1130
faa133f3
LP
1131 r = dns_question_add(question, key);
1132 if (r < 0)
1133 goto finish;
1134 }
1135 }
322345fd 1136
faa133f3
LP
1137 n = DNS_PACKET_RRCOUNT(p);
1138 if (n > 0) {
1139 answer = dns_answer_new(n);
1140 if (!answer) {
1141 r = -ENOMEM;
1142 goto finish;
1143 }
322345fd 1144
faa133f3
LP
1145 for (i = 0; i < n; i++) {
1146 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
322345fd 1147
faa133f3
LP
1148 r = dns_packet_read_rr(p, &rr, NULL);
1149 if (r < 0)
1150 goto finish;
322345fd 1151
faa133f3
LP
1152 r = dns_answer_add(answer, rr);
1153 if (r < 0)
1154 goto finish;
1155 }
322345fd
LP
1156 }
1157
faa133f3
LP
1158 p->question = question;
1159 question = NULL;
322345fd 1160
faa133f3
LP
1161 p->answer = answer;
1162 answer = NULL;
322345fd 1163
faa133f3 1164 r = 0;
322345fd
LP
1165
1166finish:
1167 p->rindex = saved_rindex;
1168 return r;
1169}
1170
74b2466e
LP
1171static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
1172 [DNS_RCODE_SUCCESS] = "SUCCESS",
1173 [DNS_RCODE_FORMERR] = "FORMERR",
1174 [DNS_RCODE_SERVFAIL] = "SERVFAIL",
1175 [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
1176 [DNS_RCODE_NOTIMP] = "NOTIMP",
1177 [DNS_RCODE_REFUSED] = "REFUSED",
1178 [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
1179 [DNS_RCODE_YXRRSET] = "YRRSET",
1180 [DNS_RCODE_NXRRSET] = "NXRRSET",
1181 [DNS_RCODE_NOTAUTH] = "NOTAUTH",
1182 [DNS_RCODE_NOTZONE] = "NOTZONE",
1183 [DNS_RCODE_BADVERS] = "BADVERS",
1184 [DNS_RCODE_BADKEY] = "BADKEY",
1185 [DNS_RCODE_BADTIME] = "BADTIME",
1186 [DNS_RCODE_BADMODE] = "BADMODE",
1187 [DNS_RCODE_BADNAME] = "BADNAME",
1188 [DNS_RCODE_BADALG] = "BADALG",
1189 [DNS_RCODE_BADTRUNC] = "BADTRUNC",
1190};
1191DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);
1716f6dc
LP
1192
1193static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
1194 [DNS_PROTOCOL_DNS] = "dns",
1195 [DNS_PROTOCOL_MDNS] = "mdns",
1196 [DNS_PROTOCOL_LLMNR] = "llmnr",
1197};
1198DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);