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 p = malloc0(ALIGN(sizeof(DnsPacket)) + a);
45 p->size = p->rindex = DNS_PACKET_HEADER_SIZE;
54 int dns_packet_new_query(DnsPacket **ret, size_t mtu) {
61 r = dns_packet_new(&p, mtu);
65 h = DNS_PACKET_HEADER(p);
66 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, 0));
72 DnsPacket *dns_packet_ref(DnsPacket *p) {
82 static void dns_packet_free(DnsPacket *p) {
87 while ((s = hashmap_steal_first_key(p->names)))
89 hashmap_free(p->names);
95 DnsPacket *dns_packet_unref(DnsPacket *p) {
109 int dns_packet_validate(DnsPacket *p) {
112 if (p->size < DNS_PACKET_HEADER_SIZE)
118 int dns_packet_validate_reply(DnsPacket *p) {
124 r = dns_packet_validate(p);
128 h = DNS_PACKET_HEADER(p);
131 if ((be16toh(h->flags) & 1) == 0)
134 /* Check opcode field */
135 if (((be16toh(h->flags) >> 1) & 15) != 0)
141 static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
144 if (p->size + add > p->allocated)
151 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size;
157 static void dns_packet_truncate(DnsPacket *p, size_t sz) {
167 HASHMAP_FOREACH_KEY(s, n, p->names, i) {
169 if (PTR_TO_SIZE(n) < sz)
172 hashmap_remove(p->names, s);
179 int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) {
185 r = dns_packet_extend(p, sizeof(uint8_t), &d, start);
189 ((uint8_t*) d)[0] = v;
194 int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
200 r = dns_packet_extend(p, sizeof(uint16_t), &d, start);
204 ((uint8_t*) d)[0] = (uint8_t) (v >> 8);
205 ((uint8_t*) d)[1] = (uint8_t) (v & 255);
210 int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
222 r = dns_packet_extend(p, 1 + l, &d, start);
226 ((uint8_t*) d)[0] = (uint8_t) l;
227 memcpy(((uint8_t*) d) + 1, s, l);
232 int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
239 if (l > DNS_LABEL_MAX)
242 r = dns_packet_extend(p, 1 + l, &w, start);
246 ((uint8_t*) w)[0] = (uint8_t) l;
247 memcpy(((uint8_t*) w) + 1, d, l);
252 int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
259 saved_size = p->size;
262 _cleanup_free_ char *s = NULL;
263 char label[DNS_LABEL_MAX];
266 n = PTR_TO_SIZE(hashmap_get(p->names, name));
271 r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
285 r = dns_label_unescape(&name, label, sizeof(label));
289 r = dns_packet_append_label(p, label, r, &n);
293 r = hashmap_ensure_allocated(&p->names, dns_name_hash_func, dns_name_compare_func);
297 r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
304 r = dns_packet_append_uint8(p, 0, NULL);
315 dns_packet_truncate(p, saved_size);
319 int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
326 saved_size = p->size;
328 r = dns_packet_append_name(p, k->name, NULL);
332 r = dns_packet_append_uint16(p, k->type, NULL);
336 r = dns_packet_append_uint16(p, k->class, NULL);
346 dns_packet_truncate(p, saved_size);
350 int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
353 if (p->rindex + sz > p->size)
357 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
366 static void dns_packet_rewind(DnsPacket *p, size_t idx) {
368 assert(idx <= p->size);
369 assert(idx >= DNS_PACKET_HEADER_SIZE);
374 int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
380 r = dns_packet_read(p, sizeof(uint8_t), &d, start);
384 *ret = ((uint8_t*) d)[0];
388 int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
394 r = dns_packet_read(p, sizeof(uint16_t), &d, start);
398 *ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) |
399 ((uint16_t) ((uint8_t*) d)[1]);
403 int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
409 r = dns_packet_read(p, sizeof(uint32_t), &d, start);
413 *ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) |
414 (((uint32_t) ((uint8_t*) d)[1]) << 16) |
415 (((uint32_t) ((uint8_t*) d)[2]) << 8) |
416 ((uint32_t) ((uint8_t*) d)[3]);
421 int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
430 saved_rindex = p->rindex;
432 r = dns_packet_read_uint8(p, &c, NULL);
436 r = dns_packet_read(p, c, &d, NULL);
440 if (memchr(d, 0, c)) {
451 if (!utf8_is_valid(t)) {
460 *start = saved_rindex;
465 dns_packet_rewind(p, saved_rindex);
469 int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
470 size_t saved_rindex, after_rindex = 0;
471 _cleanup_free_ char *ret = NULL;
472 size_t n = 0, allocated = 0;
479 saved_rindex = p->rindex;
484 r = dns_packet_read_uint8(p, &c, NULL);
492 _cleanup_free_ char *t = NULL;
496 r = dns_packet_read(p, c, (const void**) &label, NULL);
500 r = dns_label_escape(label, c, &t);
504 if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
514 memcpy(ret + n, t, c);
517 } else if ((c & 0xc0) == 0xc0) {
521 r = dns_packet_read_uint8(p, &d, NULL);
525 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
526 if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) {
531 if (after_rindex == 0)
532 after_rindex = p->rindex;
539 if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
546 if (after_rindex != 0)
547 p->rindex= after_rindex;
553 *start = saved_rindex;
558 dns_packet_rewind(p, saved_rindex);
562 int dns_packet_read_key(DnsPacket *p, DnsResourceKey *ret, size_t *start) {
563 _cleanup_(dns_resource_key_free) DnsResourceKey k = {};
570 saved_rindex = p->rindex;
572 r = dns_packet_read_name(p, &k.name, NULL);
576 r = dns_packet_read_uint16(p, &k.type, NULL);
580 r = dns_packet_read_uint16(p, &k.class, NULL);
588 *start = saved_rindex;
592 dns_packet_rewind(p, saved_rindex);
596 int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
597 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
598 size_t saved_rindex, offset;
606 saved_rindex = p->rindex;
608 rr = dns_resource_record_new();
612 r = dns_packet_read_key(p, &rr->key, NULL);
616 r = dns_packet_read_uint32(p, &rr->ttl, NULL);
620 r = dns_packet_read_uint16(p, &rdlength, NULL);
624 if (p->rindex + rdlength > p->size) {
631 switch (rr->key.type) {
636 r = dns_packet_read_name(p, &rr->ptr.name, NULL);
640 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
644 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
648 r = dns_packet_read(p, sizeof(struct in_addr), &d, NULL);
652 memcpy(&rr->a.in_addr, d, sizeof(struct in_addr));
656 r = dns_packet_read(p, sizeof(struct in6_addr), &d, NULL);
660 memcpy(&rr->aaaa.in6_addr, d, sizeof(struct in6_addr));
664 r = dns_packet_read(p, rdlength, &d, NULL);
668 rr->generic.data = memdup(d, rdlength);
669 if (!rr->generic.data) {
674 rr->generic.size = rdlength;
679 if (p->rindex != offset + rdlength) {
688 *start = saved_rindex;
692 dns_packet_rewind(p, saved_rindex);
696 int dns_packet_skip_question(DnsPacket *p) {
702 n = be16toh(DNS_PACKET_HEADER(p)->qdcount);
703 for (i = 0; i < n; i++) {
704 _cleanup_(dns_resource_key_free) DnsResourceKey key = {};
706 r = dns_packet_read_key(p, &key, NULL);
714 static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
715 [DNS_RCODE_SUCCESS] = "SUCCESS",
716 [DNS_RCODE_FORMERR] = "FORMERR",
717 [DNS_RCODE_SERVFAIL] = "SERVFAIL",
718 [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
719 [DNS_RCODE_NOTIMP] = "NOTIMP",
720 [DNS_RCODE_REFUSED] = "REFUSED",
721 [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
722 [DNS_RCODE_YXRRSET] = "YRRSET",
723 [DNS_RCODE_NXRRSET] = "NXRRSET",
724 [DNS_RCODE_NOTAUTH] = "NOTAUTH",
725 [DNS_RCODE_NOTZONE] = "NOTZONE",
726 [DNS_RCODE_BADVERS] = "BADVERS",
727 [DNS_RCODE_BADKEY] = "BADKEY",
728 [DNS_RCODE_BADTIME] = "BADTIME",
729 [DNS_RCODE_BADMODE] = "BADMODE",
730 [DNS_RCODE_BADNAME] = "BADNAME",
731 [DNS_RCODE_BADALG] = "BADALG",
732 [DNS_RCODE_BADTRUNC] = "BADTRUNC",
734 DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);