]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-packet.c
resolve-host: make arg_type an int
[thirdparty/systemd.git] / src / resolve / resolved-dns-packet.c
CommitLineData
74b2466e
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22#include "utf8.h"
c73ce96b 23#include "util.h"
2e276efc 24#include "strv.h"
74b2466e
LP
25#include "resolved-dns-domain.h"
26#include "resolved-dns-packet.h"
27
1716f6dc 28int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
74b2466e
LP
29 DnsPacket *p;
30 size_t a;
31
32 assert(ret);
33
34 if (mtu <= 0)
35 a = DNS_PACKET_SIZE_START;
36 else
37 a = mtu;
38
39 if (a < DNS_PACKET_HEADER_SIZE)
40 a = DNS_PACKET_HEADER_SIZE;
41
c73ce96b
LP
42 /* round up to next page size */
43 a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket));
44
45 /* make sure we never allocate more than useful */
46 if (a > DNS_PACKET_SIZE_MAX)
47 a = DNS_PACKET_SIZE_MAX;
48
74b2466e
LP
49 p = malloc0(ALIGN(sizeof(DnsPacket)) + a);
50 if (!p)
51 return -ENOMEM;
52
53 p->size = p->rindex = DNS_PACKET_HEADER_SIZE;
54 p->allocated = a;
1716f6dc 55 p->protocol = protocol;
74b2466e
LP
56 p->n_ref = 1;
57
58 *ret = p;
59
60 return 0;
61}
62
1716f6dc 63int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
74b2466e
LP
64 DnsPacket *p;
65 DnsPacketHeader *h;
66 int r;
67
68 assert(ret);
69
1716f6dc 70 r = dns_packet_new(&p, protocol, mtu);
74b2466e
LP
71 if (r < 0)
72 return r;
73
74 h = DNS_PACKET_HEADER(p);
1716f6dc 75
ea917db9
LP
76 if (protocol == DNS_PROTOCOL_LLMNR)
77 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,
78 0 /* opcode */,
79 0 /* c */,
80 0 /* tc */,
81 0 /* t */,
82 0 /* ra */,
83 0 /* ad */,
84 0 /* cd */,
85 0 /* rcode */));
1716f6dc 86 else
ea917db9
LP
87 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,
88 0 /* opcode */,
89 0 /* aa */,
90 0 /* tc */,
91 1 /* rd (ask for recursion) */,
92 0 /* ra */,
93 0 /* ad */,
94 0 /* cd */,
95 0 /* rcode */));
74b2466e
LP
96
97 *ret = p;
98 return 0;
99}
100
101DnsPacket *dns_packet_ref(DnsPacket *p) {
102
103 if (!p)
104 return NULL;
105
106 assert(p->n_ref > 0);
107 p->n_ref++;
108 return p;
109}
110
111static void dns_packet_free(DnsPacket *p) {
112 char *s;
113
114 assert(p);
115
faa133f3
LP
116 dns_question_unref(p->question);
117 dns_answer_unref(p->answer);
322345fd 118
74b2466e
LP
119 while ((s = hashmap_steal_first_key(p->names)))
120 free(s);
121 hashmap_free(p->names);
122
faa133f3 123 free(p->_data);
74b2466e
LP
124 free(p);
125}
126
127DnsPacket *dns_packet_unref(DnsPacket *p) {
128 if (!p)
129 return NULL;
130
131 assert(p->n_ref > 0);
132
133 if (p->n_ref == 1)
134 dns_packet_free(p);
135 else
136 p->n_ref--;
137
138 return NULL;
139}
140
141int dns_packet_validate(DnsPacket *p) {
142 assert(p);
143
144 if (p->size < DNS_PACKET_HEADER_SIZE)
145 return -EBADMSG;
146
c73ce96b
LP
147 if (p->size > DNS_PACKET_SIZE_MAX)
148 return -EBADMSG;
149
623a4c97 150 return 1;
74b2466e
LP
151}
152
153int dns_packet_validate_reply(DnsPacket *p) {
74b2466e
LP
154 int r;
155
156 assert(p);
157
158 r = dns_packet_validate(p);
159 if (r < 0)
160 return r;
161
623a4c97
LP
162 if (DNS_PACKET_QR(p) != 1)
163 return 0;
164
165 if (DNS_PACKET_OPCODE(p) != 0)
74b2466e
LP
166 return -EBADMSG;
167
ea917db9
LP
168 /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */
169 if (p->protocol == DNS_PROTOCOL_LLMNR &&
170 DNS_PACKET_QDCOUNT(p) != 1)
171 return -EBADMSG;
172
623a4c97
LP
173 return 1;
174}
175
176int dns_packet_validate_query(DnsPacket *p) {
177 int r;
178
179 assert(p);
180
181 r = dns_packet_validate(p);
182 if (r < 0)
183 return r;
184
185 if (DNS_PACKET_QR(p) != 0)
186 return 0;
187
3cb10d3a 188 if (DNS_PACKET_OPCODE(p) != 0)
74b2466e
LP
189 return -EBADMSG;
190
623a4c97
LP
191 if (DNS_PACKET_TC(p))
192 return -EBADMSG;
193
ea917db9 194 /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */
623a4c97
LP
195 if (p->protocol == DNS_PROTOCOL_LLMNR &&
196 DNS_PACKET_QDCOUNT(p) != 1)
197 return -EBADMSG;
198
ea917db9 199 /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */
623a4c97
LP
200 if (DNS_PACKET_ANCOUNT(p) > 0)
201 return -EBADMSG;
202
ea917db9 203 /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */
623a4c97
LP
204 if (DNS_PACKET_NSCOUNT(p) > 0)
205 return -EBADMSG;
206
207 return 1;
74b2466e
LP
208}
209
210static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
211 assert(p);
212
c73ce96b
LP
213 if (p->size + add > p->allocated) {
214 size_t a;
215
216 a = PAGE_ALIGN((p->size + add) * 2);
217 if (a > DNS_PACKET_SIZE_MAX)
218 a = DNS_PACKET_SIZE_MAX;
219
220 if (p->size + add > a)
221 return -EMSGSIZE;
222
faa133f3 223 if (p->_data) {
c73ce96b
LP
224 void *d;
225
faa133f3 226 d = realloc(p->_data, a);
c73ce96b
LP
227 if (!d)
228 return -ENOMEM;
229
faa133f3 230 p->_data = d;
c73ce96b 231 } else {
faa133f3
LP
232 p->_data = malloc(a);
233 if (!p->_data)
c73ce96b
LP
234 return -ENOMEM;
235
faa133f3
LP
236 memcpy(p->_data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size);
237 memzero((uint8_t*) p->_data + p->size, a - p->size);
c73ce96b
LP
238 }
239
240 p->allocated = a;
241 }
74b2466e
LP
242
243 if (start)
244 *start = p->size;
245
246 if (ret)
247 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size;
248
249 p->size += add;
250 return 0;
251}
252
253static void dns_packet_truncate(DnsPacket *p, size_t sz) {
254 Iterator i;
255 char *s;
256 void *n;
257
258 assert(p);
259
260 if (p->size <= sz)
261 return;
262
263 HASHMAP_FOREACH_KEY(s, n, p->names, i) {
264
265 if (PTR_TO_SIZE(n) < sz)
266 continue;
267
268 hashmap_remove(p->names, s);
269 free(s);
270 }
271
272 p->size = sz;
273}
274
623a4c97
LP
275int dns_packet_append_blob(DnsPacket *p, const void *d, size_t l, size_t *start) {
276 void *q;
277 int r;
278
279 assert(p);
280
281 r = dns_packet_extend(p, l, &q, start);
282 if (r < 0)
283 return r;
284
285 memcpy(q, d, l);
286 return 0;
287}
288
74b2466e
LP
289int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) {
290 void *d;
291 int r;
292
293 assert(p);
294
295 r = dns_packet_extend(p, sizeof(uint8_t), &d, start);
296 if (r < 0)
297 return r;
298
299 ((uint8_t*) d)[0] = v;
300
301 return 0;
302}
303
304int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
305 void *d;
306 int r;
307
308 assert(p);
309
310 r = dns_packet_extend(p, sizeof(uint16_t), &d, start);
311 if (r < 0)
312 return r;
313
314 ((uint8_t*) d)[0] = (uint8_t) (v >> 8);
623a4c97
LP
315 ((uint8_t*) d)[1] = (uint8_t) v;
316
317 return 0;
318}
319
320int dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start) {
321 void *d;
322 int r;
323
324 assert(p);
325
326 r = dns_packet_extend(p, sizeof(uint32_t), &d, start);
327 if (r < 0)
328 return r;
329
330 ((uint8_t*) d)[0] = (uint8_t) (v >> 24);
331 ((uint8_t*) d)[1] = (uint8_t) (v >> 16);
332 ((uint8_t*) d)[2] = (uint8_t) (v >> 8);
333 ((uint8_t*) d)[3] = (uint8_t) v;
74b2466e
LP
334
335 return 0;
336}
337
338int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
339 void *d;
340 size_t l;
341 int r;
342
343 assert(p);
344 assert(s);
345
346 l = strlen(s);
347 if (l > 255)
348 return -E2BIG;
349
350 r = dns_packet_extend(p, 1 + l, &d, start);
351 if (r < 0)
352 return r;
353
354 ((uint8_t*) d)[0] = (uint8_t) l;
355 memcpy(((uint8_t*) d) + 1, s, l);
356
357 return 0;
358}
359
360int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
361 void *w;
362 int r;
363
364 assert(p);
365 assert(d);
366
367 if (l > DNS_LABEL_MAX)
368 return -E2BIG;
369
370 r = dns_packet_extend(p, 1 + l, &w, start);
371 if (r < 0)
372 return r;
373
374 ((uint8_t*) w)[0] = (uint8_t) l;
375 memcpy(((uint8_t*) w) + 1, d, l);
376
377 return 0;
378}
379
380int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
381 size_t saved_size;
382 int r;
383
384 assert(p);
385 assert(name);
386
387 saved_size = p->size;
388
389 while (*name) {
390 _cleanup_free_ char *s = NULL;
391 char label[DNS_LABEL_MAX];
392 size_t n;
bdf10b5b 393 int k;
74b2466e
LP
394
395 n = PTR_TO_SIZE(hashmap_get(p->names, name));
396 if (n > 0) {
397 assert(n < p->size);
398
399 if (n < 0x4000) {
400 r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
401 if (r < 0)
402 goto fail;
403
404 goto done;
405 }
406 }
407
408 s = strdup(name);
409 if (!s) {
410 r = -ENOMEM;
411 goto fail;
412 }
413
414 r = dns_label_unescape(&name, label, sizeof(label));
415 if (r < 0)
416 goto fail;
417
bdf10b5b
LP
418 if (p->protocol == DNS_PROTOCOL_DNS)
419 k = dns_label_apply_idna(label, r, label, sizeof(label));
420 else
421 k = dns_label_undo_idna(label, r, label, sizeof(label));
422 if (k < 0) {
423 r = k;
424 goto fail;
425 }
426 if (k > 0)
427 r = k;
428
74b2466e
LP
429 r = dns_packet_append_label(p, label, r, &n);
430 if (r < 0)
431 goto fail;
432
433 r = hashmap_ensure_allocated(&p->names, dns_name_hash_func, dns_name_compare_func);
434 if (r < 0)
435 goto fail;
436
437 r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
438 if (r < 0)
439 goto fail;
440
441 s = NULL;
442 }
443
444 r = dns_packet_append_uint8(p, 0, NULL);
445 if (r < 0)
446 return r;
447
448done:
449 if (start)
450 *start = saved_size;
451
452 return 0;
453
454fail:
455 dns_packet_truncate(p, saved_size);
456 return r;
457}
458
459int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
460 size_t saved_size;
461 int r;
462
463 assert(p);
464 assert(k);
465
466 saved_size = p->size;
467
faa133f3 468 r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), NULL);
74b2466e
LP
469 if (r < 0)
470 goto fail;
471
472 r = dns_packet_append_uint16(p, k->type, NULL);
473 if (r < 0)
474 goto fail;
475
476 r = dns_packet_append_uint16(p, k->class, NULL);
477 if (r < 0)
478 goto fail;
479
480 if (start)
481 *start = saved_size;
482
483 return 0;
484
485fail:
486 dns_packet_truncate(p, saved_size);
487 return r;
488}
489
623a4c97
LP
490int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) {
491 size_t saved_size, rdlength_offset, end, rdlength;
492 int r;
493
494 assert(p);
495 assert(rr);
496
497 saved_size = p->size;
498
499 r = dns_packet_append_key(p, rr->key, NULL);
500 if (r < 0)
501 goto fail;
502
503 r = dns_packet_append_uint32(p, rr->ttl, NULL);
504 if (r < 0)
505 goto fail;
506
507 /* Initially we write 0 here */
508 r = dns_packet_append_uint16(p, 0, &rdlength_offset);
509 if (r < 0)
510 goto fail;
511
0dae31d4 512 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
623a4c97 513
9c92ce6d
LP
514 case DNS_TYPE_SRV:
515 r = dns_packet_append_uint16(p, rr->srv.priority, NULL);
516 if (r < 0)
517 goto fail;
518
519 r = dns_packet_append_uint16(p, rr->srv.weight, NULL);
520 if (r < 0)
521 goto fail;
522
523 r = dns_packet_append_uint16(p, rr->srv.port, NULL);
524 if (r < 0)
525 goto fail;
526
527 r = dns_packet_append_name(p, rr->srv.name, NULL);
528 break;
529
623a4c97
LP
530 case DNS_TYPE_PTR:
531 case DNS_TYPE_NS:
532 case DNS_TYPE_CNAME:
8ac4e9e1 533 case DNS_TYPE_DNAME:
623a4c97
LP
534 r = dns_packet_append_name(p, rr->ptr.name, NULL);
535 break;
536
537 case DNS_TYPE_HINFO:
538 r = dns_packet_append_string(p, rr->hinfo.cpu, NULL);
539 if (r < 0)
540 goto fail;
541
542 r = dns_packet_append_string(p, rr->hinfo.os, NULL);
543 break;
544
9de3e329 545 case DNS_TYPE_SPF: /* exactly the same as TXT */
2e276efc
ZJS
546 case DNS_TYPE_TXT: {
547 char **s;
548
549 STRV_FOREACH(s, rr->txt.strings) {
550 r = dns_packet_append_string(p, *s, NULL);
551 if (r < 0)
552 goto fail;
553 }
554
6a6fc3df 555 r = 0;
2e276efc
ZJS
556 break;
557 }
558
623a4c97
LP
559 case DNS_TYPE_A:
560 r = dns_packet_append_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
561 break;
562
563 case DNS_TYPE_AAAA:
564 r = dns_packet_append_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
565 break;
566
567 case DNS_TYPE_SOA:
568 r = dns_packet_append_name(p, rr->soa.mname, NULL);
569 if (r < 0)
570 goto fail;
571
572 r = dns_packet_append_name(p, rr->soa.rname, NULL);
573 if (r < 0)
574 goto fail;
575
576 r = dns_packet_append_uint32(p, rr->soa.serial, NULL);
577 if (r < 0)
578 goto fail;
579
580 r = dns_packet_append_uint32(p, rr->soa.refresh, NULL);
581 if (r < 0)
582 goto fail;
583
584 r = dns_packet_append_uint32(p, rr->soa.retry, NULL);
585 if (r < 0)
586 goto fail;
587
588 r = dns_packet_append_uint32(p, rr->soa.expire, NULL);
589 if (r < 0)
590 goto fail;
591
592 r = dns_packet_append_uint32(p, rr->soa.minimum, NULL);
593 break;
594
595 case DNS_TYPE_MX:
946c7094
ZJS
596 r = dns_packet_append_uint16(p, rr->mx.priority, NULL);
597 if (r < 0)
598 goto fail;
599
600 r = dns_packet_append_name(p, rr->mx.exchange, NULL);
601 break;
602
0dae31d4
ZJS
603 case DNS_TYPE_LOC:
604 r = dns_packet_append_uint8(p, rr->loc.version, NULL);
605 if (r < 0)
606 goto fail;
607
608 r = dns_packet_append_uint8(p, rr->loc.size, NULL);
609 if (r < 0)
610 goto fail;
611
612 r = dns_packet_append_uint8(p, rr->loc.horiz_pre, NULL);
613 if (r < 0)
614 goto fail;
615
616 r = dns_packet_append_uint8(p, rr->loc.vert_pre, NULL);
617 if (r < 0)
618 goto fail;
619
afbc4f26 620 r = dns_packet_append_uint32(p, rr->loc.latitude, NULL);
0dae31d4
ZJS
621 if (r < 0)
622 goto fail;
623
afbc4f26 624 r = dns_packet_append_uint32(p, rr->loc.longitude, NULL);
0dae31d4
ZJS
625 if (r < 0)
626 goto fail;
627
afbc4f26 628 r = dns_packet_append_uint32(p, rr->loc.altitude, NULL);
0dae31d4
ZJS
629 break;
630
623a4c97 631 case DNS_TYPE_SSHFP:
42cc2eeb
LP
632 r = dns_packet_append_uint8(p, rr->sshfp.algorithm, NULL);
633 if (r < 0)
634 goto fail;
635 r = dns_packet_append_uint8(p, rr->sshfp.fptype, NULL);
636 if (r < 0)
637 goto fail;
638
639 r = dns_packet_append_blob(p, rr->sshfp.key, rr->sshfp.key_size, NULL);
640 break;
641
0dae31d4 642 case _DNS_TYPE_INVALID: /* unparseable */
623a4c97 643 default:
0dae31d4 644
623a4c97
LP
645 r = dns_packet_append_blob(p, rr->generic.data, rr->generic.size, NULL);
646 break;
647 }
648 if (r < 0)
649 goto fail;
650
651 /* Let's calculate the actual data size and update the field */
652 rdlength = p->size - rdlength_offset - sizeof(uint16_t);
653 if (rdlength > 0xFFFF) {
654 r = ENOSPC;
655 goto fail;
656 }
657
658 end = p->size;
659 p->size = rdlength_offset;
660 r = dns_packet_append_uint16(p, rdlength, NULL);
661 if (r < 0)
662 goto fail;
663 p->size = end;
664
351e6342
LP
665 if (start)
666 *start = saved_size;
667
623a4c97
LP
668 return 0;
669
670fail:
671 dns_packet_truncate(p, saved_size);
672 return r;
673}
674
675
74b2466e
LP
676int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
677 assert(p);
678
679 if (p->rindex + sz > p->size)
680 return -EMSGSIZE;
681
682 if (ret)
683 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
684
685 if (start)
686 *start = p->rindex;
687
688 p->rindex += sz;
689 return 0;
690}
691
8ba9fd9c 692void dns_packet_rewind(DnsPacket *p, size_t idx) {
74b2466e
LP
693 assert(p);
694 assert(idx <= p->size);
695 assert(idx >= DNS_PACKET_HEADER_SIZE);
696
697 p->rindex = idx;
698}
699
623a4c97
LP
700int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start) {
701 const void *q;
702 int r;
703
704 assert(p);
705 assert(d);
706
707 r = dns_packet_read(p, sz, &q, start);
708 if (r < 0)
709 return r;
710
711 memcpy(d, q, sz);
712 return 0;
713}
714
74b2466e
LP
715int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
716 const void *d;
717 int r;
718
719 assert(p);
720
721 r = dns_packet_read(p, sizeof(uint8_t), &d, start);
722 if (r < 0)
723 return r;
724
725 *ret = ((uint8_t*) d)[0];
726 return 0;
727}
728
729int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
730 const void *d;
731 int r;
732
733 assert(p);
734
735 r = dns_packet_read(p, sizeof(uint16_t), &d, start);
736 if (r < 0)
737 return r;
738
739 *ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) |
740 ((uint16_t) ((uint8_t*) d)[1]);
741 return 0;
742}
743
744int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
745 const void *d;
746 int r;
747
748 assert(p);
749
750 r = dns_packet_read(p, sizeof(uint32_t), &d, start);
751 if (r < 0)
752 return r;
753
754 *ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) |
755 (((uint32_t) ((uint8_t*) d)[1]) << 16) |
756 (((uint32_t) ((uint8_t*) d)[2]) << 8) |
757 ((uint32_t) ((uint8_t*) d)[3]);
758
759 return 0;
760}
761
762int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
763 size_t saved_rindex;
764 const void *d;
765 char *t;
766 uint8_t c;
767 int r;
768
769 assert(p);
770
771 saved_rindex = p->rindex;
772
773 r = dns_packet_read_uint8(p, &c, NULL);
774 if (r < 0)
775 goto fail;
776
777 r = dns_packet_read(p, c, &d, NULL);
778 if (r < 0)
779 goto fail;
780
781 if (memchr(d, 0, c)) {
782 r = -EBADMSG;
783 goto fail;
784 }
785
786 t = strndup(d, c);
787 if (!t) {
788 r = -ENOMEM;
789 goto fail;
790 }
791
792 if (!utf8_is_valid(t)) {
793 free(t);
794 r = -EBADMSG;
795 goto fail;
796 }
797
798 *ret = t;
799
800 if (start)
801 *start = saved_rindex;
802
803 return 0;
804
805fail:
806 dns_packet_rewind(p, saved_rindex);
807 return r;
808}
809
810int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
811 size_t saved_rindex, after_rindex = 0;
812 _cleanup_free_ char *ret = NULL;
813 size_t n = 0, allocated = 0;
814 bool first = true;
815 int r;
816
817 assert(p);
818 assert(_ret);
819
820 saved_rindex = p->rindex;
821
822 for (;;) {
823 uint8_t c, d;
824
825 r = dns_packet_read_uint8(p, &c, NULL);
826 if (r < 0)
827 goto fail;
828
829 if (c == 0)
830 /* End of name */
831 break;
832 else if (c <= 63) {
833 _cleanup_free_ char *t = NULL;
834 const char *label;
835
836 /* Literal label */
837 r = dns_packet_read(p, c, (const void**) &label, NULL);
838 if (r < 0)
839 goto fail;
840
841 r = dns_label_escape(label, c, &t);
842 if (r < 0)
843 goto fail;
844
845 if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
846 r = -ENOMEM;
847 goto fail;
848 }
849
850 if (!first)
851 ret[n++] = '.';
852 else
853 first = false;
854
85818582 855 memcpy(ret + n, t, r);
74b2466e
LP
856 n += r;
857 continue;
858 } else if ((c & 0xc0) == 0xc0) {
859 uint16_t ptr;
860
861 /* Pointer */
862 r = dns_packet_read_uint8(p, &d, NULL);
863 if (r < 0)
864 goto fail;
865
866 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
867 if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) {
868 r = -EBADMSG;
869 goto fail;
870 }
871
872 if (after_rindex == 0)
873 after_rindex = p->rindex;
874
875 p->rindex = ptr;
876 } else
877 goto fail;
878 }
879
880 if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
881 r = -ENOMEM;
882 goto fail;
883 }
884
885 ret[n] = 0;
886
887 if (after_rindex != 0)
888 p->rindex= after_rindex;
889
890 *_ret = ret;
891 ret = NULL;
892
893 if (start)
894 *start = saved_rindex;
895
896 return 0;
897
898fail:
899 dns_packet_rewind(p, saved_rindex);
900 return r;
901}
902
faa133f3
LP
903int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
904 _cleanup_free_ char *name = NULL;
905 uint16_t class, type;
906 DnsResourceKey *key;
74b2466e
LP
907 size_t saved_rindex;
908 int r;
909
910 assert(p);
911 assert(ret);
912
913 saved_rindex = p->rindex;
914
faa133f3 915 r = dns_packet_read_name(p, &name, NULL);
74b2466e
LP
916 if (r < 0)
917 goto fail;
918
faa133f3 919 r = dns_packet_read_uint16(p, &type, NULL);
74b2466e
LP
920 if (r < 0)
921 goto fail;
922
faa133f3 923 r = dns_packet_read_uint16(p, &class, NULL);
74b2466e
LP
924 if (r < 0)
925 goto fail;
926
faa133f3
LP
927 key = dns_resource_key_new_consume(class, type, name);
928 if (!key) {
929 r = -ENOMEM;
930 goto fail;
931 }
932
933 name = NULL;
934 *ret = key;
74b2466e
LP
935
936 if (start)
937 *start = saved_rindex;
938
939 return 0;
940fail:
941 dns_packet_rewind(p, saved_rindex);
942 return r;
943}
944
afbc4f26
ZJS
945static bool loc_size_ok(uint8_t size) {
946 uint8_t m = size >> 4, e = size & 0xF;
947
948 return m <= 9 && e <= 9 && (m > 0 || e == 0);
949}
950
74b2466e 951int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
faa133f3
LP
952 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
953 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
74b2466e
LP
954 size_t saved_rindex, offset;
955 uint16_t rdlength;
956 const void *d;
957 int r;
958
959 assert(p);
960 assert(ret);
961
4e0296a9 962 saved_rindex = p->rindex;
74b2466e 963
faa133f3 964 r = dns_packet_read_key(p, &key, NULL);
74b2466e
LP
965 if (r < 0)
966 goto fail;
967
0e2bcd6a
LP
968 if (key->class == DNS_CLASS_ANY ||
969 key->type == DNS_TYPE_ANY) {
970 r = -EBADMSG;
971 goto fail;
972 }
973
faa133f3
LP
974 rr = dns_resource_record_new(key);
975 if (!rr) {
976 r = -ENOMEM;
977 goto fail;
978 }
979
74b2466e
LP
980 r = dns_packet_read_uint32(p, &rr->ttl, NULL);
981 if (r < 0)
982 goto fail;
983
984 r = dns_packet_read_uint16(p, &rdlength, NULL);
985 if (r < 0)
986 goto fail;
987
988 if (p->rindex + rdlength > p->size) {
989 r = -EBADMSG;
990 goto fail;
991 }
992
993 offset = p->rindex;
994
faa133f3 995 switch (rr->key->type) {
74b2466e 996
9c92ce6d
LP
997 case DNS_TYPE_SRV:
998 r = dns_packet_read_uint16(p, &rr->srv.priority, NULL);
999 if (r < 0)
1000 goto fail;
1001 r = dns_packet_read_uint16(p, &rr->srv.weight, NULL);
1002 if (r < 0)
1003 goto fail;
1004 r = dns_packet_read_uint16(p, &rr->srv.port, NULL);
1005 if (r < 0)
1006 goto fail;
1007 r = dns_packet_read_name(p, &rr->srv.name, NULL);
1008 break;
1009
74b2466e
LP
1010 case DNS_TYPE_PTR:
1011 case DNS_TYPE_NS:
1012 case DNS_TYPE_CNAME:
8ac4e9e1 1013 case DNS_TYPE_DNAME:
74b2466e
LP
1014 r = dns_packet_read_name(p, &rr->ptr.name, NULL);
1015 break;
1016
1017 case DNS_TYPE_HINFO:
1018 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
1019 if (r < 0)
1020 goto fail;
1021
1022 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
1023 break;
1024
9de3e329 1025 case DNS_TYPE_SPF: /* exactly the same as TXT */
2e276efc
ZJS
1026 case DNS_TYPE_TXT: {
1027 char *s;
1028
cbd67a86 1029 while (p->rindex < offset + rdlength) {
2e276efc
ZJS
1030 r = dns_packet_read_string(p, &s, NULL);
1031 if (r < 0)
1032 goto fail;
1033
1034 r = strv_consume(&rr->txt.strings, s);
1035 if (r < 0)
1036 goto fail;
6a6fc3df
LP
1037 }
1038
1039 r = 0;
2e276efc
ZJS
1040 break;
1041 }
1042
74b2466e 1043 case DNS_TYPE_A:
623a4c97 1044 r = dns_packet_read_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
74b2466e
LP
1045 break;
1046
1047 case DNS_TYPE_AAAA:
623a4c97 1048 r = dns_packet_read_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
74b2466e
LP
1049 break;
1050
7e8e0422
LP
1051 case DNS_TYPE_SOA:
1052 r = dns_packet_read_name(p, &rr->soa.mname, NULL);
1053 if (r < 0)
1054 goto fail;
1055
1056 r = dns_packet_read_name(p, &rr->soa.rname, NULL);
1057 if (r < 0)
1058 goto fail;
1059
1060 r = dns_packet_read_uint32(p, &rr->soa.serial, NULL);
1061 if (r < 0)
1062 goto fail;
1063
1064 r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL);
1065 if (r < 0)
1066 goto fail;
1067
1068 r = dns_packet_read_uint32(p, &rr->soa.retry, NULL);
1069 if (r < 0)
1070 goto fail;
1071
1072 r = dns_packet_read_uint32(p, &rr->soa.expire, NULL);
1073 if (r < 0)
1074 goto fail;
1075
1076 r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL);
1077 break;
1078
623a4c97 1079 case DNS_TYPE_MX:
946c7094
ZJS
1080 r = dns_packet_read_uint16(p, &rr->mx.priority, NULL);
1081 if (r < 0)
1082 goto fail;
1083
1084 r = dns_packet_read_name(p, &rr->mx.exchange, NULL);
1085 break;
1086
0dae31d4
ZJS
1087 case DNS_TYPE_LOC: {
1088 uint8_t t;
1089 size_t pos;
1090
1091 r = dns_packet_read_uint8(p, &t, &pos);
1092 if (r < 0)
1093 goto fail;
1094
1095 if (t == 0) {
1096 rr->loc.version = t;
1097
1098 r = dns_packet_read_uint8(p, &rr->loc.size, NULL);
1099 if (r < 0)
1100 goto fail;
1101
afbc4f26
ZJS
1102 if (!loc_size_ok(rr->loc.size)) {
1103 r = -EBADMSG;
1104 goto fail;
1105 }
1106
0dae31d4
ZJS
1107 r = dns_packet_read_uint8(p, &rr->loc.horiz_pre, NULL);
1108 if (r < 0)
1109 goto fail;
1110
afbc4f26
ZJS
1111 if (!loc_size_ok(rr->loc.horiz_pre)) {
1112 r = -EBADMSG;
1113 goto fail;
1114 }
1115
0dae31d4
ZJS
1116 r = dns_packet_read_uint8(p, &rr->loc.vert_pre, NULL);
1117 if (r < 0)
1118 goto fail;
1119
afbc4f26
ZJS
1120 if (!loc_size_ok(rr->loc.vert_pre)) {
1121 r = -EBADMSG;
1122 goto fail;
1123 }
1124
0dae31d4
ZJS
1125 r = dns_packet_read_uint32(p, &rr->loc.latitude, NULL);
1126 if (r < 0)
1127 goto fail;
1128
1129 r = dns_packet_read_uint32(p, &rr->loc.longitude, NULL);
1130 if (r < 0)
1131 goto fail;
1132
1133 r = dns_packet_read_uint32(p, &rr->loc.altitude, NULL);
1134 if (r < 0)
1135 goto fail;
1136
1137 break;
1138 } else {
1139 dns_packet_rewind(p, pos);
1140 rr->unparseable = true;
afbc4f26 1141 goto unparseable;
0dae31d4
ZJS
1142 }
1143 }
1144
623a4c97 1145 case DNS_TYPE_SSHFP:
42cc2eeb
LP
1146
1147 r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL);
1148 if (r < 0)
1149 goto fail;
1150
1151 r = dns_packet_read_uint8(p, &rr->sshfp.fptype, NULL);
1152 if (r < 0)
1153 goto fail;
1154
1155 r = dns_packet_read(p, rdlength - 2, &d, NULL);
1156 if (r < 0)
1157 goto fail;
1158
1159 rr->sshfp.key = memdup(d, rdlength - 2);
1160 if (!rr->sshfp.key) {
1161 r = -ENOMEM;
1162 goto fail;
1163 }
1164
1165 rr->sshfp.key_size = rdlength - 2;
1166 break;
1167
74b2466e 1168 default:
afbc4f26 1169 unparseable:
74b2466e
LP
1170 r = dns_packet_read(p, rdlength, &d, NULL);
1171 if (r < 0)
1172 goto fail;
1173
1174 rr->generic.data = memdup(d, rdlength);
1175 if (!rr->generic.data) {
1176 r = -ENOMEM;
1177 goto fail;
1178 }
1179
1180 rr->generic.size = rdlength;
1181 break;
1182 }
1183 if (r < 0)
1184 goto fail;
1185 if (p->rindex != offset + rdlength) {
1186 r = -EBADMSG;
1187 goto fail;
1188 }
1189
1190 *ret = rr;
1191 rr = NULL;
1192
1193 if (start)
1194 *start = saved_rindex;
1195
1196 return 0;
1197fail:
1198 dns_packet_rewind(p, saved_rindex);
1199 return r;
1200}
1201
faa133f3
LP
1202int dns_packet_extract(DnsPacket *p) {
1203 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
1204 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
1205 size_t saved_rindex;
1206 unsigned n, i;
74b2466e
LP
1207 int r;
1208
faa133f3 1209 saved_rindex = p->rindex;
322345fd
LP
1210 dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
1211
3cb10d3a 1212 n = DNS_PACKET_QDCOUNT(p);
faa133f3
LP
1213 if (n > 0) {
1214 question = dns_question_new(n);
1215 if (!question) {
1216 r = -ENOMEM;
1217 goto finish;
1218 }
74b2466e 1219
faa133f3
LP
1220 for (i = 0; i < n; i++) {
1221 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
74b2466e 1222
faa133f3
LP
1223 r = dns_packet_read_key(p, &key, NULL);
1224 if (r < 0)
1225 goto finish;
74b2466e 1226
faa133f3
LP
1227 r = dns_question_add(question, key);
1228 if (r < 0)
1229 goto finish;
1230 }
1231 }
322345fd 1232
faa133f3
LP
1233 n = DNS_PACKET_RRCOUNT(p);
1234 if (n > 0) {
1235 answer = dns_answer_new(n);
1236 if (!answer) {
1237 r = -ENOMEM;
1238 goto finish;
1239 }
322345fd 1240
faa133f3
LP
1241 for (i = 0; i < n; i++) {
1242 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
322345fd 1243
faa133f3
LP
1244 r = dns_packet_read_rr(p, &rr, NULL);
1245 if (r < 0)
1246 goto finish;
322345fd 1247
faa133f3
LP
1248 r = dns_answer_add(answer, rr);
1249 if (r < 0)
1250 goto finish;
1251 }
322345fd
LP
1252 }
1253
faa133f3
LP
1254 p->question = question;
1255 question = NULL;
322345fd 1256
faa133f3
LP
1257 p->answer = answer;
1258 answer = NULL;
322345fd 1259
faa133f3 1260 r = 0;
322345fd
LP
1261
1262finish:
1263 p->rindex = saved_rindex;
1264 return r;
1265}
1266
74b2466e
LP
1267static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
1268 [DNS_RCODE_SUCCESS] = "SUCCESS",
1269 [DNS_RCODE_FORMERR] = "FORMERR",
1270 [DNS_RCODE_SERVFAIL] = "SERVFAIL",
1271 [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
1272 [DNS_RCODE_NOTIMP] = "NOTIMP",
1273 [DNS_RCODE_REFUSED] = "REFUSED",
1274 [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
1275 [DNS_RCODE_YXRRSET] = "YRRSET",
1276 [DNS_RCODE_NXRRSET] = "NXRRSET",
1277 [DNS_RCODE_NOTAUTH] = "NOTAUTH",
1278 [DNS_RCODE_NOTZONE] = "NOTZONE",
1279 [DNS_RCODE_BADVERS] = "BADVERS",
1280 [DNS_RCODE_BADKEY] = "BADKEY",
1281 [DNS_RCODE_BADTIME] = "BADTIME",
1282 [DNS_RCODE_BADMODE] = "BADMODE",
1283 [DNS_RCODE_BADNAME] = "BADNAME",
1284 [DNS_RCODE_BADALG] = "BADALG",
1285 [DNS_RCODE_BADTRUNC] = "BADTRUNC",
1286};
1287DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);
1716f6dc
LP
1288
1289static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
1290 [DNS_PROTOCOL_DNS] = "dns",
1291 [DNS_PROTOCOL_MDNS] = "mdns",
1292 [DNS_PROTOCOL_LLMNR] = "llmnr",
1293};
1294DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);