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, DnsProtocol protocol, 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;
54 p->protocol = protocol;
62 int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
69 r = dns_packet_new(&p, protocol, mtu);
73 h = DNS_PACKET_HEADER(p);
75 if (protocol == DNS_PROTOCOL_DNS)
76 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, 0)); /* ask for recursion */
78 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0));
84 DnsPacket *dns_packet_ref(DnsPacket *p) {
94 static void dns_packet_free(DnsPacket *p) {
99 dns_question_unref(p->question);
100 dns_answer_unref(p->answer);
102 while ((s = hashmap_steal_first_key(p->names)))
104 hashmap_free(p->names);
110 DnsPacket *dns_packet_unref(DnsPacket *p) {
114 assert(p->n_ref > 0);
124 int dns_packet_validate(DnsPacket *p) {
127 if (p->size < DNS_PACKET_HEADER_SIZE)
130 if (p->size > DNS_PACKET_SIZE_MAX)
136 int dns_packet_validate_reply(DnsPacket *p) {
141 r = dns_packet_validate(p);
145 if (DNS_PACKET_QR(p) == 0)
148 if (DNS_PACKET_OPCODE(p) != 0)
154 static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
157 if (p->size + add > p->allocated) {
160 a = PAGE_ALIGN((p->size + add) * 2);
161 if (a > DNS_PACKET_SIZE_MAX)
162 a = DNS_PACKET_SIZE_MAX;
164 if (p->size + add > a)
170 d = realloc(p->_data, a);
176 p->_data = malloc(a);
180 memcpy(p->_data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size);
181 memzero((uint8_t*) p->_data + p->size, a - p->size);
191 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size;
197 static void dns_packet_truncate(DnsPacket *p, size_t sz) {
207 HASHMAP_FOREACH_KEY(s, n, p->names, i) {
209 if (PTR_TO_SIZE(n) < sz)
212 hashmap_remove(p->names, s);
219 int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) {
225 r = dns_packet_extend(p, sizeof(uint8_t), &d, start);
229 ((uint8_t*) d)[0] = v;
234 int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
240 r = dns_packet_extend(p, sizeof(uint16_t), &d, start);
244 ((uint8_t*) d)[0] = (uint8_t) (v >> 8);
245 ((uint8_t*) d)[1] = (uint8_t) (v & 255);
250 int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
262 r = dns_packet_extend(p, 1 + l, &d, start);
266 ((uint8_t*) d)[0] = (uint8_t) l;
267 memcpy(((uint8_t*) d) + 1, s, l);
272 int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
279 if (l > DNS_LABEL_MAX)
282 r = dns_packet_extend(p, 1 + l, &w, start);
286 ((uint8_t*) w)[0] = (uint8_t) l;
287 memcpy(((uint8_t*) w) + 1, d, l);
292 int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
299 saved_size = p->size;
302 _cleanup_free_ char *s = NULL;
303 char label[DNS_LABEL_MAX];
306 n = PTR_TO_SIZE(hashmap_get(p->names, name));
311 r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
325 r = dns_label_unescape(&name, label, sizeof(label));
329 r = dns_packet_append_label(p, label, r, &n);
333 r = hashmap_ensure_allocated(&p->names, dns_name_hash_func, dns_name_compare_func);
337 r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
344 r = dns_packet_append_uint8(p, 0, NULL);
355 dns_packet_truncate(p, saved_size);
359 int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
366 saved_size = p->size;
368 r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), NULL);
372 r = dns_packet_append_uint16(p, k->type, NULL);
376 r = dns_packet_append_uint16(p, k->class, NULL);
386 dns_packet_truncate(p, saved_size);
390 int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
393 if (p->rindex + sz > p->size)
397 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
406 void dns_packet_rewind(DnsPacket *p, size_t idx) {
408 assert(idx <= p->size);
409 assert(idx >= DNS_PACKET_HEADER_SIZE);
414 int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
420 r = dns_packet_read(p, sizeof(uint8_t), &d, start);
424 *ret = ((uint8_t*) d)[0];
428 int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
434 r = dns_packet_read(p, sizeof(uint16_t), &d, start);
438 *ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) |
439 ((uint16_t) ((uint8_t*) d)[1]);
443 int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
449 r = dns_packet_read(p, sizeof(uint32_t), &d, start);
453 *ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) |
454 (((uint32_t) ((uint8_t*) d)[1]) << 16) |
455 (((uint32_t) ((uint8_t*) d)[2]) << 8) |
456 ((uint32_t) ((uint8_t*) d)[3]);
461 int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
470 saved_rindex = p->rindex;
472 r = dns_packet_read_uint8(p, &c, NULL);
476 r = dns_packet_read(p, c, &d, NULL);
480 if (memchr(d, 0, c)) {
491 if (!utf8_is_valid(t)) {
500 *start = saved_rindex;
505 dns_packet_rewind(p, saved_rindex);
509 int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
510 size_t saved_rindex, after_rindex = 0;
511 _cleanup_free_ char *ret = NULL;
512 size_t n = 0, allocated = 0;
519 saved_rindex = p->rindex;
524 r = dns_packet_read_uint8(p, &c, NULL);
532 _cleanup_free_ char *t = NULL;
536 r = dns_packet_read(p, c, (const void**) &label, NULL);
540 r = dns_label_escape(label, c, &t);
544 if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
554 memcpy(ret + n, t, c);
557 } else if ((c & 0xc0) == 0xc0) {
561 r = dns_packet_read_uint8(p, &d, NULL);
565 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
566 if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) {
571 if (after_rindex == 0)
572 after_rindex = p->rindex;
579 if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
586 if (after_rindex != 0)
587 p->rindex= after_rindex;
593 *start = saved_rindex;
598 dns_packet_rewind(p, saved_rindex);
602 int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
603 _cleanup_free_ char *name = NULL;
604 uint16_t class, type;
612 saved_rindex = p->rindex;
614 r = dns_packet_read_name(p, &name, NULL);
618 r = dns_packet_read_uint16(p, &type, NULL);
622 r = dns_packet_read_uint16(p, &class, NULL);
626 key = dns_resource_key_new_consume(class, type, name);
636 *start = saved_rindex;
640 dns_packet_rewind(p, saved_rindex);
644 int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
645 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
646 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
647 size_t saved_rindex, offset;
655 saved_rindex = p->rindex;
657 r = dns_packet_read_key(p, &key, NULL);
661 rr = dns_resource_record_new(key);
667 r = dns_packet_read_uint32(p, &rr->ttl, NULL);
671 r = dns_packet_read_uint16(p, &rdlength, NULL);
675 if (p->rindex + rdlength > p->size) {
682 switch (rr->key->type) {
687 r = dns_packet_read_name(p, &rr->ptr.name, NULL);
691 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
695 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
699 r = dns_packet_read(p, sizeof(struct in_addr), &d, NULL);
703 memcpy(&rr->a.in_addr, d, sizeof(struct in_addr));
707 r = dns_packet_read(p, sizeof(struct in6_addr), &d, NULL);
711 memcpy(&rr->aaaa.in6_addr, d, sizeof(struct in6_addr));
715 r = dns_packet_read_name(p, &rr->soa.mname, NULL);
719 r = dns_packet_read_name(p, &rr->soa.rname, NULL);
723 r = dns_packet_read_uint32(p, &rr->soa.serial, NULL);
727 r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL);
731 r = dns_packet_read_uint32(p, &rr->soa.retry, NULL);
735 r = dns_packet_read_uint32(p, &rr->soa.expire, NULL);
739 r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL);
743 r = dns_packet_read(p, rdlength, &d, NULL);
747 rr->generic.data = memdup(d, rdlength);
748 if (!rr->generic.data) {
753 rr->generic.size = rdlength;
758 if (p->rindex != offset + rdlength) {
767 *start = saved_rindex;
771 dns_packet_rewind(p, saved_rindex);
775 int dns_packet_extract(DnsPacket *p) {
776 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
777 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
782 saved_rindex = p->rindex;
783 dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
785 n = DNS_PACKET_QDCOUNT(p);
787 question = dns_question_new(n);
793 for (i = 0; i < n; i++) {
794 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
796 r = dns_packet_read_key(p, &key, NULL);
800 r = dns_question_add(question, key);
806 n = DNS_PACKET_RRCOUNT(p);
808 answer = dns_answer_new(n);
814 for (i = 0; i < n; i++) {
815 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
817 r = dns_packet_read_rr(p, &rr, NULL);
821 r = dns_answer_add(answer, rr);
827 p->question = question;
836 p->rindex = saved_rindex;
840 static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
841 [DNS_RCODE_SUCCESS] = "SUCCESS",
842 [DNS_RCODE_FORMERR] = "FORMERR",
843 [DNS_RCODE_SERVFAIL] = "SERVFAIL",
844 [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
845 [DNS_RCODE_NOTIMP] = "NOTIMP",
846 [DNS_RCODE_REFUSED] = "REFUSED",
847 [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
848 [DNS_RCODE_YXRRSET] = "YRRSET",
849 [DNS_RCODE_NXRRSET] = "NXRRSET",
850 [DNS_RCODE_NOTAUTH] = "NOTAUTH",
851 [DNS_RCODE_NOTZONE] = "NOTZONE",
852 [DNS_RCODE_BADVERS] = "BADVERS",
853 [DNS_RCODE_BADKEY] = "BADKEY",
854 [DNS_RCODE_BADTIME] = "BADTIME",
855 [DNS_RCODE_BADMODE] = "BADMODE",
856 [DNS_RCODE_BADNAME] = "BADNAME",
857 [DNS_RCODE_BADALG] = "BADALG",
858 [DNS_RCODE_BADTRUNC] = "BADTRUNC",
860 DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);
862 static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
863 [DNS_PROTOCOL_DNS] = "dns",
864 [DNS_PROTOCOL_MDNS] = "mdns",
865 [DNS_PROTOCOL_LLMNR] = "llmnr",
867 DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);