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