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