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) {
94 while ((s = hashmap_steal_first_key(p->names)))
96 hashmap_free(p->names);
102 DnsPacket *dns_packet_unref(DnsPacket *p) {
106 assert(p->n_ref > 0);
116 int dns_packet_validate(DnsPacket *p) {
119 if (p->size < DNS_PACKET_HEADER_SIZE)
122 if (p->size > DNS_PACKET_SIZE_MAX)
128 int dns_packet_validate_reply(DnsPacket *p) {
133 r = dns_packet_validate(p);
137 if (DNS_PACKET_QR(p) == 0)
140 if (DNS_PACKET_OPCODE(p) != 0)
146 static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
149 if (p->size + add > p->allocated) {
152 a = PAGE_ALIGN((p->size + add) * 2);
153 if (a > DNS_PACKET_SIZE_MAX)
154 a = DNS_PACKET_SIZE_MAX;
156 if (p->size + add > a)
162 d = realloc(p->data, a);
172 memcpy(p->data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size);
173 memzero((uint8_t*) p->data + p->size, a - p->size);
183 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size;
189 static void dns_packet_truncate(DnsPacket *p, size_t sz) {
199 HASHMAP_FOREACH_KEY(s, n, p->names, i) {
201 if (PTR_TO_SIZE(n) < sz)
204 hashmap_remove(p->names, s);
211 int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) {
217 r = dns_packet_extend(p, sizeof(uint8_t), &d, start);
221 ((uint8_t*) d)[0] = v;
226 int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
232 r = dns_packet_extend(p, sizeof(uint16_t), &d, start);
236 ((uint8_t*) d)[0] = (uint8_t) (v >> 8);
237 ((uint8_t*) d)[1] = (uint8_t) (v & 255);
242 int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
254 r = dns_packet_extend(p, 1 + l, &d, start);
258 ((uint8_t*) d)[0] = (uint8_t) l;
259 memcpy(((uint8_t*) d) + 1, s, l);
264 int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
271 if (l > DNS_LABEL_MAX)
274 r = dns_packet_extend(p, 1 + l, &w, start);
278 ((uint8_t*) w)[0] = (uint8_t) l;
279 memcpy(((uint8_t*) w) + 1, d, l);
284 int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
291 saved_size = p->size;
294 _cleanup_free_ char *s = NULL;
295 char label[DNS_LABEL_MAX];
298 n = PTR_TO_SIZE(hashmap_get(p->names, name));
303 r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
317 r = dns_label_unescape(&name, label, sizeof(label));
321 r = dns_packet_append_label(p, label, r, &n);
325 r = hashmap_ensure_allocated(&p->names, dns_name_hash_func, dns_name_compare_func);
329 r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
336 r = dns_packet_append_uint8(p, 0, NULL);
347 dns_packet_truncate(p, saved_size);
351 int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
358 saved_size = p->size;
360 r = dns_packet_append_name(p, k->name, NULL);
364 r = dns_packet_append_uint16(p, k->type, NULL);
368 r = dns_packet_append_uint16(p, k->class, NULL);
378 dns_packet_truncate(p, saved_size);
382 int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
385 if (p->rindex + sz > p->size)
389 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
398 void dns_packet_rewind(DnsPacket *p, size_t idx) {
400 assert(idx <= p->size);
401 assert(idx >= DNS_PACKET_HEADER_SIZE);
406 int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
412 r = dns_packet_read(p, sizeof(uint8_t), &d, start);
416 *ret = ((uint8_t*) d)[0];
420 int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
426 r = dns_packet_read(p, sizeof(uint16_t), &d, start);
430 *ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) |
431 ((uint16_t) ((uint8_t*) d)[1]);
435 int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
441 r = dns_packet_read(p, sizeof(uint32_t), &d, start);
445 *ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) |
446 (((uint32_t) ((uint8_t*) d)[1]) << 16) |
447 (((uint32_t) ((uint8_t*) d)[2]) << 8) |
448 ((uint32_t) ((uint8_t*) d)[3]);
453 int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
462 saved_rindex = p->rindex;
464 r = dns_packet_read_uint8(p, &c, NULL);
468 r = dns_packet_read(p, c, &d, NULL);
472 if (memchr(d, 0, c)) {
483 if (!utf8_is_valid(t)) {
492 *start = saved_rindex;
497 dns_packet_rewind(p, saved_rindex);
501 int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
502 size_t saved_rindex, after_rindex = 0;
503 _cleanup_free_ char *ret = NULL;
504 size_t n = 0, allocated = 0;
511 saved_rindex = p->rindex;
516 r = dns_packet_read_uint8(p, &c, NULL);
524 _cleanup_free_ char *t = NULL;
528 r = dns_packet_read(p, c, (const void**) &label, NULL);
532 r = dns_label_escape(label, c, &t);
536 if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
546 memcpy(ret + n, t, c);
549 } else if ((c & 0xc0) == 0xc0) {
553 r = dns_packet_read_uint8(p, &d, NULL);
557 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
558 if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) {
563 if (after_rindex == 0)
564 after_rindex = p->rindex;
571 if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
578 if (after_rindex != 0)
579 p->rindex= after_rindex;
585 *start = saved_rindex;
590 dns_packet_rewind(p, saved_rindex);
594 int dns_packet_read_key(DnsPacket *p, DnsResourceKey *ret, size_t *start) {
595 _cleanup_(dns_resource_key_free) DnsResourceKey k = {};
602 saved_rindex = p->rindex;
604 r = dns_packet_read_name(p, &k.name, NULL);
608 r = dns_packet_read_uint16(p, &k.type, NULL);
612 r = dns_packet_read_uint16(p, &k.class, NULL);
620 *start = saved_rindex;
624 dns_packet_rewind(p, saved_rindex);
628 int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
629 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr;
630 size_t saved_rindex, offset;
638 rr = dns_resource_record_new();
642 saved_rindex = p->rindex;
644 r = dns_packet_read_key(p, &rr->key, NULL);
648 r = dns_packet_read_uint32(p, &rr->ttl, NULL);
652 r = dns_packet_read_uint16(p, &rdlength, NULL);
656 if (p->rindex + rdlength > p->size) {
663 switch (rr->key.type) {
668 r = dns_packet_read_name(p, &rr->ptr.name, NULL);
672 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
676 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
680 r = dns_packet_read(p, sizeof(struct in_addr), &d, NULL);
684 memcpy(&rr->a.in_addr, d, sizeof(struct in_addr));
688 r = dns_packet_read(p, sizeof(struct in6_addr), &d, NULL);
692 memcpy(&rr->aaaa.in6_addr, d, sizeof(struct in6_addr));
696 r = dns_packet_read(p, rdlength, &d, NULL);
700 rr->generic.data = memdup(d, rdlength);
701 if (!rr->generic.data) {
706 rr->generic.size = rdlength;
711 if (p->rindex != offset + rdlength) {
720 *start = saved_rindex;
724 dns_packet_rewind(p, saved_rindex);
728 int dns_packet_skip_question(DnsPacket *p) {
734 n = DNS_PACKET_QDCOUNT(p);
735 for (i = 0; i < n; i++) {
736 _cleanup_(dns_resource_key_free) DnsResourceKey key = {};
738 r = dns_packet_read_key(p, &key, NULL);
746 static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
747 [DNS_RCODE_SUCCESS] = "SUCCESS",
748 [DNS_RCODE_FORMERR] = "FORMERR",
749 [DNS_RCODE_SERVFAIL] = "SERVFAIL",
750 [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
751 [DNS_RCODE_NOTIMP] = "NOTIMP",
752 [DNS_RCODE_REFUSED] = "REFUSED",
753 [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
754 [DNS_RCODE_YXRRSET] = "YRRSET",
755 [DNS_RCODE_NXRRSET] = "NXRRSET",
756 [DNS_RCODE_NOTAUTH] = "NOTAUTH",
757 [DNS_RCODE_NOTZONE] = "NOTZONE",
758 [DNS_RCODE_BADVERS] = "BADVERS",
759 [DNS_RCODE_BADKEY] = "BADKEY",
760 [DNS_RCODE_BADTIME] = "BADTIME",
761 [DNS_RCODE_BADMODE] = "BADMODE",
762 [DNS_RCODE_BADNAME] = "BADNAME",
763 [DNS_RCODE_BADALG] = "BADALG",
764 [DNS_RCODE_BADTRUNC] = "BADTRUNC",
766 DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);