1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
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.
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.
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/>.
24 #include "resolved-dns-domain.h"
25 #include "resolved-dns-packet.h"
27 int dns_packet_new(DnsPacket **ret, size_t mtu) {
34 a = DNS_PACKET_SIZE_START;
38 if (a < DNS_PACKET_HEADER_SIZE)
39 a = DNS_PACKET_HEADER_SIZE;
41 /* round up to next page size */
42 a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket));
44 /* make sure we never allocate more than useful */
45 if (a > DNS_PACKET_SIZE_MAX)
46 a = DNS_PACKET_SIZE_MAX;
48 p = malloc0(ALIGN(sizeof(DnsPacket)) + a);
52 p->size = p->rindex = DNS_PACKET_HEADER_SIZE;
61 int dns_packet_new_query(DnsPacket **ret, size_t mtu) {
68 r = dns_packet_new(&p, mtu);
72 h = DNS_PACKET_HEADER(p);
73 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, 0));
79 DnsPacket *dns_packet_ref(DnsPacket *p) {
89 static void dns_packet_free(DnsPacket *p) {
95 dns_resource_record_freev(p->rrs, DNS_PACKET_RRCOUNT(p));
97 while ((s = hashmap_steal_first_key(p->names)))
99 hashmap_free(p->names);
105 DnsPacket *dns_packet_unref(DnsPacket *p) {
109 assert(p->n_ref > 0);
119 int dns_packet_validate(DnsPacket *p) {
122 if (p->size < DNS_PACKET_HEADER_SIZE)
125 if (p->size > DNS_PACKET_SIZE_MAX)
131 int dns_packet_validate_reply(DnsPacket *p) {
136 r = dns_packet_validate(p);
140 if (DNS_PACKET_QR(p) == 0)
143 if (DNS_PACKET_OPCODE(p) != 0)
149 static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
152 if (p->size + add > p->allocated) {
155 a = PAGE_ALIGN((p->size + add) * 2);
156 if (a > DNS_PACKET_SIZE_MAX)
157 a = DNS_PACKET_SIZE_MAX;
159 if (p->size + add > a)
165 d = realloc(p->data, a);
175 memcpy(p->data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size);
176 memzero((uint8_t*) p->data + p->size, a - p->size);
186 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size;
192 static void dns_packet_truncate(DnsPacket *p, size_t sz) {
202 HASHMAP_FOREACH_KEY(s, n, p->names, i) {
204 if (PTR_TO_SIZE(n) < sz)
207 hashmap_remove(p->names, s);
214 int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) {
220 r = dns_packet_extend(p, sizeof(uint8_t), &d, start);
224 ((uint8_t*) d)[0] = v;
229 int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
235 r = dns_packet_extend(p, sizeof(uint16_t), &d, start);
239 ((uint8_t*) d)[0] = (uint8_t) (v >> 8);
240 ((uint8_t*) d)[1] = (uint8_t) (v & 255);
245 int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
257 r = dns_packet_extend(p, 1 + l, &d, start);
261 ((uint8_t*) d)[0] = (uint8_t) l;
262 memcpy(((uint8_t*) d) + 1, s, l);
267 int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
274 if (l > DNS_LABEL_MAX)
277 r = dns_packet_extend(p, 1 + l, &w, start);
281 ((uint8_t*) w)[0] = (uint8_t) l;
282 memcpy(((uint8_t*) w) + 1, d, l);
287 int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
294 saved_size = p->size;
297 _cleanup_free_ char *s = NULL;
298 char label[DNS_LABEL_MAX];
301 n = PTR_TO_SIZE(hashmap_get(p->names, name));
306 r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
320 r = dns_label_unescape(&name, label, sizeof(label));
324 r = dns_packet_append_label(p, label, r, &n);
328 r = hashmap_ensure_allocated(&p->names, dns_name_hash_func, dns_name_compare_func);
332 r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
339 r = dns_packet_append_uint8(p, 0, NULL);
350 dns_packet_truncate(p, saved_size);
354 int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
361 saved_size = p->size;
363 r = dns_packet_append_name(p, k->name, NULL);
367 r = dns_packet_append_uint16(p, k->type, NULL);
371 r = dns_packet_append_uint16(p, k->class, NULL);
381 dns_packet_truncate(p, saved_size);
385 int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
388 if (p->rindex + sz > p->size)
392 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
401 void dns_packet_rewind(DnsPacket *p, size_t idx) {
403 assert(idx <= p->size);
404 assert(idx >= DNS_PACKET_HEADER_SIZE);
409 int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
415 r = dns_packet_read(p, sizeof(uint8_t), &d, start);
419 *ret = ((uint8_t*) d)[0];
423 int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
429 r = dns_packet_read(p, sizeof(uint16_t), &d, start);
433 *ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) |
434 ((uint16_t) ((uint8_t*) d)[1]);
438 int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
444 r = dns_packet_read(p, sizeof(uint32_t), &d, start);
448 *ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) |
449 (((uint32_t) ((uint8_t*) d)[1]) << 16) |
450 (((uint32_t) ((uint8_t*) d)[2]) << 8) |
451 ((uint32_t) ((uint8_t*) d)[3]);
456 int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
465 saved_rindex = p->rindex;
467 r = dns_packet_read_uint8(p, &c, NULL);
471 r = dns_packet_read(p, c, &d, NULL);
475 if (memchr(d, 0, c)) {
486 if (!utf8_is_valid(t)) {
495 *start = saved_rindex;
500 dns_packet_rewind(p, saved_rindex);
504 int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
505 size_t saved_rindex, after_rindex = 0;
506 _cleanup_free_ char *ret = NULL;
507 size_t n = 0, allocated = 0;
514 saved_rindex = p->rindex;
519 r = dns_packet_read_uint8(p, &c, NULL);
527 _cleanup_free_ char *t = NULL;
531 r = dns_packet_read(p, c, (const void**) &label, NULL);
535 r = dns_label_escape(label, c, &t);
539 if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
549 memcpy(ret + n, t, c);
552 } else if ((c & 0xc0) == 0xc0) {
556 r = dns_packet_read_uint8(p, &d, NULL);
560 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
561 if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) {
566 if (after_rindex == 0)
567 after_rindex = p->rindex;
574 if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
581 if (after_rindex != 0)
582 p->rindex= after_rindex;
588 *start = saved_rindex;
593 dns_packet_rewind(p, saved_rindex);
597 int dns_packet_read_key(DnsPacket *p, DnsResourceKey *ret, size_t *start) {
598 _cleanup_(dns_resource_key_free) DnsResourceKey k = {};
605 saved_rindex = p->rindex;
607 r = dns_packet_read_name(p, &k.name, NULL);
611 r = dns_packet_read_uint16(p, &k.type, NULL);
615 r = dns_packet_read_uint16(p, &k.class, NULL);
623 *start = saved_rindex;
627 dns_packet_rewind(p, saved_rindex);
631 int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
632 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr;
633 size_t saved_rindex, offset;
641 rr = dns_resource_record_new();
645 saved_rindex = p->rindex;
647 r = dns_packet_read_key(p, &rr->key, NULL);
651 r = dns_packet_read_uint32(p, &rr->ttl, NULL);
655 r = dns_packet_read_uint16(p, &rdlength, NULL);
659 if (p->rindex + rdlength > p->size) {
666 switch (rr->key.type) {
671 r = dns_packet_read_name(p, &rr->ptr.name, NULL);
675 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
679 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
683 r = dns_packet_read(p, sizeof(struct in_addr), &d, NULL);
687 memcpy(&rr->a.in_addr, d, sizeof(struct in_addr));
691 r = dns_packet_read(p, sizeof(struct in6_addr), &d, NULL);
695 memcpy(&rr->aaaa.in6_addr, d, sizeof(struct in6_addr));
699 r = dns_packet_read(p, rdlength, &d, NULL);
703 rr->generic.data = memdup(d, rdlength);
704 if (!rr->generic.data) {
709 rr->generic.size = rdlength;
714 if (p->rindex != offset + rdlength) {
723 *start = saved_rindex;
727 dns_packet_rewind(p, saved_rindex);
731 int dns_packet_skip_question(DnsPacket *p) {
737 dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
739 n = DNS_PACKET_QDCOUNT(p);
740 for (i = 0; i < n; i++) {
741 _cleanup_(dns_resource_key_free) DnsResourceKey key = {};
743 r = dns_packet_read_key(p, &key, NULL);
751 int dns_packet_extract_rrs(DnsPacket *p) {
752 DnsResourceRecord **rrs = NULL;
754 unsigned n, added = 0;
758 return (int) DNS_PACKET_RRCOUNT(p);
760 saved_rindex = p->rindex;
762 r = dns_packet_skip_question(p);
766 n = DNS_PACKET_RRCOUNT(p);
772 rrs = new0(DnsResourceRecord*, n);
778 for (added = 0; added < n; added++) {
779 r = dns_packet_read_rr(p, &rrs[added], NULL);
781 dns_resource_record_freev(rrs, added);
790 p->rindex = saved_rindex;
794 static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
795 [DNS_RCODE_SUCCESS] = "SUCCESS",
796 [DNS_RCODE_FORMERR] = "FORMERR",
797 [DNS_RCODE_SERVFAIL] = "SERVFAIL",
798 [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
799 [DNS_RCODE_NOTIMP] = "NOTIMP",
800 [DNS_RCODE_REFUSED] = "REFUSED",
801 [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
802 [DNS_RCODE_YXRRSET] = "YRRSET",
803 [DNS_RCODE_NXRRSET] = "NXRRSET",
804 [DNS_RCODE_NOTAUTH] = "NOTAUTH",
805 [DNS_RCODE_NOTZONE] = "NOTZONE",
806 [DNS_RCODE_BADVERS] = "BADVERS",
807 [DNS_RCODE_BADKEY] = "BADKEY",
808 [DNS_RCODE_BADTIME] = "BADTIME",
809 [DNS_RCODE_BADMODE] = "BADMODE",
810 [DNS_RCODE_BADNAME] = "BADNAME",
811 [DNS_RCODE_BADALG] = "BADALG",
812 [DNS_RCODE_BADTRUNC] = "BADTRUNC",
814 DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);