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