diff options
Diffstat (limited to 'src/resolve/resolved-dns-rr.c')
-rw-r--r-- | src/resolve/resolved-dns-rr.c | 1521 |
1 files changed, 0 insertions, 1521 deletions
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c deleted file mode 100644 index 40f8e28dfd..0000000000 --- a/src/resolve/resolved-dns-rr.c +++ /dev/null @@ -1,1521 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <math.h> - -#include "alloc-util.h" -#include "dns-domain.h" -#include "dns-type.h" -#include "hexdecoct.h" -#include "resolved-dns-dnssec.h" -#include "resolved-dns-packet.h" -#include "resolved-dns-rr.h" -#include "string-table.h" -#include "string-util.h" -#include "strv.h" -#include "terminal-util.h" - -DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) { - DnsResourceKey *k; - size_t l; - - assert(name); - - l = strlen(name); - k = malloc0(sizeof(DnsResourceKey) + l + 1); - if (!k) - return NULL; - - k->n_ref = 1; - k->class = class; - k->type = type; - - strcpy((char*) k + sizeof(DnsResourceKey), name); - - return k; -} - -DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) { - int r; - - assert(key); - assert(cname); - - assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME)); - - if (cname->key->type == DNS_TYPE_CNAME) - return dns_resource_key_new(key->class, key->type, cname->cname.name); - else { - DnsResourceKey *k; - char *destination = NULL; - - r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination); - if (r < 0) - return NULL; - if (r == 0) - return dns_resource_key_ref((DnsResourceKey*) key); - - k = dns_resource_key_new_consume(key->class, key->type, destination); - if (!k) { - free(destination); - return NULL; - } - - return k; - } -} - -int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name) { - DnsResourceKey *new_key; - char *joined; - int r; - - assert(ret); - assert(key); - assert(name); - - if (dns_name_is_root(name)) { - *ret = dns_resource_key_ref(key); - return 0; - } - - r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), name, &joined); - if (r < 0) - return r; - - new_key = dns_resource_key_new_consume(key->class, key->type, joined); - if (!new_key) { - free(joined); - return -ENOMEM; - } - - *ret = new_key; - return 0; -} - -DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) { - DnsResourceKey *k; - - assert(name); - - k = new0(DnsResourceKey, 1); - if (!k) - return NULL; - - k->n_ref = 1; - k->class = class; - k->type = type; - k->_name = name; - - return k; -} - -DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) { - - if (!k) - return NULL; - - /* Static/const keys created with DNS_RESOURCE_KEY_CONST will - * set this to -1, they should not be reffed/unreffed */ - assert(k->n_ref != (unsigned) -1); - - assert(k->n_ref > 0); - k->n_ref++; - - return k; -} - -DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) { - if (!k) - return NULL; - - assert(k->n_ref != (unsigned) -1); - assert(k->n_ref > 0); - - if (k->n_ref == 1) { - free(k->_name); - free(k); - } else - k->n_ref--; - - return NULL; -} - -bool dns_resource_key_is_address(const DnsResourceKey *key) { - assert(key); - - /* Check if this is an A or AAAA resource key */ - - return key->class == DNS_CLASS_IN && IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_AAAA); -} - -int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) { - int r; - - if (a == b) - return 1; - - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b)); - if (r <= 0) - return r; - - if (a->class != b->class) - return 0; - - if (a->type != b->type) - return 0; - - return 1; -} - -int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, const char *search_domain) { - int r; - - assert(key); - assert(rr); - - if (key == rr->key) - return 1; - - /* Checks if an rr matches the specified key. If a search - * domain is specified, it will also be checked if the key - * with the search domain suffixed might match the RR. */ - - if (rr->key->class != key->class && key->class != DNS_CLASS_ANY) - return 0; - - if (rr->key->type != key->type && key->type != DNS_TYPE_ANY) - return 0; - - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key)); - if (r != 0) - return r; - - if (search_domain) { - _cleanup_free_ char *joined = NULL; - - r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined); - if (r < 0) - return r; - - return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), joined); - } - - return 0; -} - -int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain) { - int r; - - assert(key); - assert(cname); - - if (cname->class != key->class && key->class != DNS_CLASS_ANY) - return 0; - - if (cname->type == DNS_TYPE_CNAME) - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname)); - else if (cname->type == DNS_TYPE_DNAME) - r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname)); - else - return 0; - - if (r != 0) - return r; - - if (search_domain) { - _cleanup_free_ char *joined = NULL; - - r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined); - if (r < 0) - return r; - - if (cname->type == DNS_TYPE_CNAME) - return dns_name_equal(joined, DNS_RESOURCE_KEY_NAME(cname)); - else if (cname->type == DNS_TYPE_DNAME) - return dns_name_endswith(joined, DNS_RESOURCE_KEY_NAME(cname)); - } - - return 0; -} - -int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *soa) { - assert(soa); - assert(key); - - /* Checks whether 'soa' is a SOA record for the specified key. */ - - if (soa->class != key->class) - return 0; - - if (soa->type != DNS_TYPE_SOA) - return 0; - - return dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(soa)); -} - -static void dns_resource_key_hash_func(const void *i, struct siphash *state) { - const DnsResourceKey *k = i; - - assert(k); - - dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state); - siphash24_compress(&k->class, sizeof(k->class), state); - siphash24_compress(&k->type, sizeof(k->type), state); -} - -static int dns_resource_key_compare_func(const void *a, const void *b) { - const DnsResourceKey *x = a, *y = b; - int ret; - - ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y)); - if (ret != 0) - return ret; - - if (x->type < y->type) - return -1; - if (x->type > y->type) - return 1; - - if (x->class < y->class) - return -1; - if (x->class > y->class) - return 1; - - return 0; -} - -const struct hash_ops dns_resource_key_hash_ops = { - .hash = dns_resource_key_hash_func, - .compare = dns_resource_key_compare_func -}; - -int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) { - char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)]; - const char *c, *t, *n; - char *s; - - /* If we cannot convert the CLASS/TYPE into a known string, - use the format recommended by RFC 3597, Section 5. */ - - c = dns_class_to_string(key->class); - if (!c) { - sprintf(cbuf, "CLASS%u", key->class); - c = cbuf; - } - - t = dns_type_to_string(key->type); - if (!t){ - sprintf(tbuf, "TYPE%u", key->type); - t = tbuf; - } - - n = DNS_RESOURCE_KEY_NAME(key); - if (asprintf(&s, "%s%s %s %-5s", n, endswith(n, ".") ? "" : ".", c, t) < 0) - return -ENOMEM; - - *ret = s; - return 0; -} - -bool dns_resource_key_reduce(DnsResourceKey **a, DnsResourceKey **b) { - assert(a); - assert(b); - - /* Try to replace one RR key by another if they are identical, thus saving a bit of memory. Note that we do - * this only for RR keys, not for RRs themselves, as they carry a lot of additional metadata (where they come - * from, validity data, and suchlike), and cannot be replaced so easily by other RRs that have the same - * superficial data. */ - - if (!*a) - return false; - if (!*b) - return false; - - /* We refuse merging const keys */ - if ((*a)->n_ref == (unsigned) -1) - return false; - if ((*b)->n_ref == (unsigned) -1) - return false; - - /* Already the same? */ - if (*a == *b) - return true; - - /* Are they really identical? */ - if (dns_resource_key_equal(*a, *b) <= 0) - return false; - - /* Keep the one which already has more references. */ - if ((*a)->n_ref > (*b)->n_ref) { - dns_resource_key_unref(*b); - *b = dns_resource_key_ref(*a); - } else { - dns_resource_key_unref(*a); - *a = dns_resource_key_ref(*b); - } - - return true; -} - -DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) { - DnsResourceRecord *rr; - - rr = new0(DnsResourceRecord, 1); - if (!rr) - return NULL; - - rr->n_ref = 1; - rr->key = dns_resource_key_ref(key); - rr->expiry = USEC_INFINITY; - rr->n_skip_labels_signer = rr->n_skip_labels_source = (unsigned) -1; - - return rr; -} - -DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) { - _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; - - key = dns_resource_key_new(class, type, name); - if (!key) - return NULL; - - return dns_resource_record_new(key); -} - -DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) { - if (!rr) - return NULL; - - assert(rr->n_ref > 0); - rr->n_ref++; - - return rr; -} - -DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) { - if (!rr) - return NULL; - - assert(rr->n_ref > 0); - - if (rr->n_ref > 1) { - rr->n_ref--; - return NULL; - } - - if (rr->key) { - switch(rr->key->type) { - - case DNS_TYPE_SRV: - free(rr->srv.name); - break; - - case DNS_TYPE_PTR: - case DNS_TYPE_NS: - case DNS_TYPE_CNAME: - case DNS_TYPE_DNAME: - free(rr->ptr.name); - break; - - case DNS_TYPE_HINFO: - free(rr->hinfo.cpu); - free(rr->hinfo.os); - break; - - case DNS_TYPE_TXT: - case DNS_TYPE_SPF: - dns_txt_item_free_all(rr->txt.items); - break; - - case DNS_TYPE_SOA: - free(rr->soa.mname); - free(rr->soa.rname); - break; - - case DNS_TYPE_MX: - free(rr->mx.exchange); - break; - - case DNS_TYPE_DS: - free(rr->ds.digest); - break; - - case DNS_TYPE_SSHFP: - free(rr->sshfp.fingerprint); - break; - - case DNS_TYPE_DNSKEY: - free(rr->dnskey.key); - break; - - case DNS_TYPE_RRSIG: - free(rr->rrsig.signer); - free(rr->rrsig.signature); - break; - - case DNS_TYPE_NSEC: - free(rr->nsec.next_domain_name); - bitmap_free(rr->nsec.types); - break; - - case DNS_TYPE_NSEC3: - free(rr->nsec3.next_hashed_name); - free(rr->nsec3.salt); - bitmap_free(rr->nsec3.types); - break; - - case DNS_TYPE_LOC: - case DNS_TYPE_A: - case DNS_TYPE_AAAA: - break; - - case DNS_TYPE_TLSA: - free(rr->tlsa.data); - break; - - case DNS_TYPE_OPENPGPKEY: - default: - free(rr->generic.data); - } - - free(rr->wire_format); - dns_resource_key_unref(rr->key); - } - - free(rr->to_string); - free(rr); - - return NULL; -} - -int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) { - _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; - _cleanup_free_ char *ptr = NULL; - int r; - - assert(ret); - assert(address); - assert(hostname); - - r = dns_name_reverse(family, address, &ptr); - if (r < 0) - return r; - - key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr); - if (!key) - return -ENOMEM; - - ptr = NULL; - - rr = dns_resource_record_new(key); - if (!rr) - return -ENOMEM; - - rr->ptr.name = strdup(hostname); - if (!rr->ptr.name) - return -ENOMEM; - - *ret = rr; - rr = NULL; - - return 0; -} - -int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) { - DnsResourceRecord *rr; - - assert(ret); - assert(address); - assert(family); - - if (family == AF_INET) { - - rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name); - if (!rr) - return -ENOMEM; - - rr->a.in_addr = address->in; - - } else if (family == AF_INET6) { - - rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name); - if (!rr) - return -ENOMEM; - - rr->aaaa.in6_addr = address->in6; - } else - return -EAFNOSUPPORT; - - *ret = rr; - - return 0; -} - -#define FIELD_EQUAL(a, b, field) \ - ((a).field ## _size == (b).field ## _size && \ - memcmp((a).field, (b).field, (a).field ## _size) == 0) - -int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) { - int r; - - assert(a); - assert(b); - - if (a == b) - return 1; - - r = dns_resource_key_equal(a->key, b->key); - if (r <= 0) - return r; - - if (a->unparseable != b->unparseable) - return 0; - - switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) { - - case DNS_TYPE_SRV: - r = dns_name_equal(a->srv.name, b->srv.name); - if (r <= 0) - return r; - - return a->srv.priority == b->srv.priority && - a->srv.weight == b->srv.weight && - a->srv.port == b->srv.port; - - case DNS_TYPE_PTR: - case DNS_TYPE_NS: - case DNS_TYPE_CNAME: - case DNS_TYPE_DNAME: - return dns_name_equal(a->ptr.name, b->ptr.name); - - case DNS_TYPE_HINFO: - return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) && - strcaseeq(a->hinfo.os, b->hinfo.os); - - case DNS_TYPE_SPF: /* exactly the same as TXT */ - case DNS_TYPE_TXT: - return dns_txt_item_equal(a->txt.items, b->txt.items); - - case DNS_TYPE_A: - return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0; - - case DNS_TYPE_AAAA: - return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0; - - case DNS_TYPE_SOA: - r = dns_name_equal(a->soa.mname, b->soa.mname); - if (r <= 0) - return r; - r = dns_name_equal(a->soa.rname, b->soa.rname); - if (r <= 0) - return r; - - return a->soa.serial == b->soa.serial && - a->soa.refresh == b->soa.refresh && - a->soa.retry == b->soa.retry && - a->soa.expire == b->soa.expire && - a->soa.minimum == b->soa.minimum; - - case DNS_TYPE_MX: - if (a->mx.priority != b->mx.priority) - return 0; - - return dns_name_equal(a->mx.exchange, b->mx.exchange); - - case DNS_TYPE_LOC: - assert(a->loc.version == b->loc.version); - - return a->loc.size == b->loc.size && - a->loc.horiz_pre == b->loc.horiz_pre && - a->loc.vert_pre == b->loc.vert_pre && - a->loc.latitude == b->loc.latitude && - a->loc.longitude == b->loc.longitude && - a->loc.altitude == b->loc.altitude; - - case DNS_TYPE_DS: - return a->ds.key_tag == b->ds.key_tag && - a->ds.algorithm == b->ds.algorithm && - a->ds.digest_type == b->ds.digest_type && - FIELD_EQUAL(a->ds, b->ds, digest); - - case DNS_TYPE_SSHFP: - return a->sshfp.algorithm == b->sshfp.algorithm && - a->sshfp.fptype == b->sshfp.fptype && - FIELD_EQUAL(a->sshfp, b->sshfp, fingerprint); - - case DNS_TYPE_DNSKEY: - return a->dnskey.flags == b->dnskey.flags && - a->dnskey.protocol == b->dnskey.protocol && - a->dnskey.algorithm == b->dnskey.algorithm && - FIELD_EQUAL(a->dnskey, b->dnskey, key); - - case DNS_TYPE_RRSIG: - /* do the fast comparisons first */ - return a->rrsig.type_covered == b->rrsig.type_covered && - a->rrsig.algorithm == b->rrsig.algorithm && - a->rrsig.labels == b->rrsig.labels && - a->rrsig.original_ttl == b->rrsig.original_ttl && - a->rrsig.expiration == b->rrsig.expiration && - a->rrsig.inception == b->rrsig.inception && - a->rrsig.key_tag == b->rrsig.key_tag && - FIELD_EQUAL(a->rrsig, b->rrsig, signature) && - dns_name_equal(a->rrsig.signer, b->rrsig.signer); - - case DNS_TYPE_NSEC: - return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) && - bitmap_equal(a->nsec.types, b->nsec.types); - - case DNS_TYPE_NSEC3: - return a->nsec3.algorithm == b->nsec3.algorithm && - a->nsec3.flags == b->nsec3.flags && - a->nsec3.iterations == b->nsec3.iterations && - FIELD_EQUAL(a->nsec3, b->nsec3, salt) && - FIELD_EQUAL(a->nsec3, b->nsec3, next_hashed_name) && - bitmap_equal(a->nsec3.types, b->nsec3.types); - - case DNS_TYPE_TLSA: - return a->tlsa.cert_usage == b->tlsa.cert_usage && - a->tlsa.selector == b->tlsa.selector && - a->tlsa.matching_type == b->tlsa.matching_type && - FIELD_EQUAL(a->tlsa, b->tlsa, data); - - default: - return FIELD_EQUAL(a->generic, b->generic, data); - } -} - -static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude, - uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) { - char *s; - char NS = latitude >= 1U<<31 ? 'N' : 'S'; - char EW = longitude >= 1U<<31 ? 'E' : 'W'; - - int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude); - int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude); - double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude); - double siz = (size >> 4) * exp10((double) (size & 0xF)); - double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF)); - double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF)); - - if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm", - (lat / 60000 / 60), - (lat / 60000) % 60, - (lat % 60000) / 1000., - NS, - (lon / 60000 / 60), - (lon / 60000) % 60, - (lon % 60000) / 1000., - EW, - alt / 100., - siz / 100., - hor / 100., - ver / 100.) < 0) - return NULL; - - return s; -} - -static int format_timestamp_dns(char *buf, size_t l, time_t sec) { - struct tm tm; - - assert(buf); - assert(l > strlen("YYYYMMDDHHmmSS")); - - if (!gmtime_r(&sec, &tm)) - return -EINVAL; - - if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0) - return -EINVAL; - - return 0; -} - -static char *format_types(Bitmap *types) { - _cleanup_strv_free_ char **strv = NULL; - _cleanup_free_ char *str = NULL; - Iterator i; - unsigned type; - int r; - - BITMAP_FOREACH(type, types, i) { - if (dns_type_to_string(type)) { - r = strv_extend(&strv, dns_type_to_string(type)); - if (r < 0) - return NULL; - } else { - char *t; - - r = asprintf(&t, "TYPE%u", type); - if (r < 0) - return NULL; - - r = strv_consume(&strv, t); - if (r < 0) - return NULL; - } - } - - str = strv_join(strv, " "); - if (!str) - return NULL; - - return strjoin("( ", str, " )", NULL); -} - -static char *format_txt(DnsTxtItem *first) { - DnsTxtItem *i; - size_t c = 1; - char *p, *s; - - LIST_FOREACH(items, i, first) - c += i->length * 4 + 3; - - p = s = new(char, c); - if (!s) - return NULL; - - LIST_FOREACH(items, i, first) { - size_t j; - - if (i != first) - *(p++) = ' '; - - *(p++) = '"'; - - for (j = 0; j < i->length; j++) { - if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) { - *(p++) = '\\'; - *(p++) = '0' + (i->data[j] / 100); - *(p++) = '0' + ((i->data[j] / 10) % 10); - *(p++) = '0' + (i->data[j] % 10); - } else - *(p++) = i->data[j]; - } - - *(p++) = '"'; - } - - *p = 0; - return s; -} - -const char *dns_resource_record_to_string(DnsResourceRecord *rr) { - _cleanup_free_ char *k = NULL, *t = NULL; - char *s; - int r; - - assert(rr); - - if (rr->to_string) - return rr->to_string; - - r = dns_resource_key_to_string(rr->key, &k); - if (r < 0) - return NULL; - - switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) { - - case DNS_TYPE_SRV: - r = asprintf(&s, "%s %u %u %u %s", - k, - rr->srv.priority, - rr->srv.weight, - rr->srv.port, - strna(rr->srv.name)); - if (r < 0) - return NULL; - break; - - case DNS_TYPE_PTR: - case DNS_TYPE_NS: - case DNS_TYPE_CNAME: - case DNS_TYPE_DNAME: - s = strjoin(k, " ", rr->ptr.name, NULL); - if (!s) - return NULL; - - break; - - case DNS_TYPE_HINFO: - s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL); - if (!s) - return NULL; - break; - - case DNS_TYPE_SPF: /* exactly the same as TXT */ - case DNS_TYPE_TXT: - t = format_txt(rr->txt.items); - if (!t) - return NULL; - - s = strjoin(k, " ", t, NULL); - if (!s) - return NULL; - break; - - case DNS_TYPE_A: { - _cleanup_free_ char *x = NULL; - - r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x); - if (r < 0) - return NULL; - - s = strjoin(k, " ", x, NULL); - if (!s) - return NULL; - break; - } - - case DNS_TYPE_AAAA: - r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t); - if (r < 0) - return NULL; - - s = strjoin(k, " ", t, NULL); - if (!s) - return NULL; - break; - - case DNS_TYPE_SOA: - r = asprintf(&s, "%s %s %s %u %u %u %u %u", - k, - strna(rr->soa.mname), - strna(rr->soa.rname), - rr->soa.serial, - rr->soa.refresh, - rr->soa.retry, - rr->soa.expire, - rr->soa.minimum); - if (r < 0) - return NULL; - break; - - case DNS_TYPE_MX: - r = asprintf(&s, "%s %u %s", - k, - rr->mx.priority, - rr->mx.exchange); - if (r < 0) - return NULL; - break; - - case DNS_TYPE_LOC: - assert(rr->loc.version == 0); - - t = format_location(rr->loc.latitude, - rr->loc.longitude, - rr->loc.altitude, - rr->loc.size, - rr->loc.horiz_pre, - rr->loc.vert_pre); - if (!t) - return NULL; - - s = strjoin(k, " ", t, NULL); - if (!s) - return NULL; - break; - - case DNS_TYPE_DS: - t = hexmem(rr->ds.digest, rr->ds.digest_size); - if (!t) - return NULL; - - r = asprintf(&s, "%s %u %u %u %s", - k, - rr->ds.key_tag, - rr->ds.algorithm, - rr->ds.digest_type, - t); - if (r < 0) - return NULL; - break; - - case DNS_TYPE_SSHFP: - t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size); - if (!t) - return NULL; - - r = asprintf(&s, "%s %u %u %s", - k, - rr->sshfp.algorithm, - rr->sshfp.fptype, - t); - if (r < 0) - return NULL; - break; - - case DNS_TYPE_DNSKEY: { - _cleanup_free_ char *alg = NULL; - char *ss; - int n, n1; - uint16_t key_tag; - - key_tag = dnssec_keytag(rr, true); - - r = dnssec_algorithm_to_string_alloc(rr->dnskey.algorithm, &alg); - if (r < 0) - return NULL; - - r = asprintf(&s, "%s %n%u %u %s %n", - k, - &n1, - rr->dnskey.flags, - rr->dnskey.protocol, - alg, - &n); - if (r < 0) - return NULL; - - r = base64_append(&s, n, - rr->dnskey.key, rr->dnskey.key_size, - 8, columns()); - if (r < 0) - return NULL; - - r = asprintf(&ss, "%s\n" - "%*s-- Flags:%s%s%s\n" - "%*s-- Key tag: %u", - s, - n1, "", - rr->dnskey.flags & DNSKEY_FLAG_SEP ? " SEP" : "", - rr->dnskey.flags & DNSKEY_FLAG_REVOKE ? " REVOKE" : "", - rr->dnskey.flags & DNSKEY_FLAG_ZONE_KEY ? " ZONE_KEY" : "", - n1, "", - key_tag); - if (r < 0) - return NULL; - free(s); - s = ss; - - break; - } - - case DNS_TYPE_RRSIG: { - _cleanup_free_ char *alg = NULL; - char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1]; - const char *type; - int n; - - type = dns_type_to_string(rr->rrsig.type_covered); - - r = dnssec_algorithm_to_string_alloc(rr->rrsig.algorithm, &alg); - if (r < 0) - return NULL; - - r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration); - if (r < 0) - return NULL; - - r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception); - if (r < 0) - return NULL; - - /* TYPE?? follows - * http://tools.ietf.org/html/rfc3597#section-5 */ - - r = asprintf(&s, "%s %s%.*u %s %u %u %s %s %u %s %n", - k, - type ?: "TYPE", - type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered, - alg, - rr->rrsig.labels, - rr->rrsig.original_ttl, - expiration, - inception, - rr->rrsig.key_tag, - rr->rrsig.signer, - &n); - if (r < 0) - return NULL; - - r = base64_append(&s, n, - rr->rrsig.signature, rr->rrsig.signature_size, - 8, columns()); - if (r < 0) - return NULL; - - break; - } - - case DNS_TYPE_NSEC: - t = format_types(rr->nsec.types); - if (!t) - return NULL; - - r = asprintf(&s, "%s %s %s", - k, - rr->nsec.next_domain_name, - t); - if (r < 0) - return NULL; - break; - - case DNS_TYPE_NSEC3: { - _cleanup_free_ char *salt = NULL, *hash = NULL; - - if (rr->nsec3.salt_size > 0) { - salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size); - if (!salt) - return NULL; - } - - hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false); - if (!hash) - return NULL; - - t = format_types(rr->nsec3.types); - if (!t) - return NULL; - - r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s", - k, - rr->nsec3.algorithm, - rr->nsec3.flags, - rr->nsec3.iterations, - rr->nsec3.salt_size > 0 ? salt : "-", - hash, - t); - if (r < 0) - return NULL; - - break; - } - - case DNS_TYPE_TLSA: { - const char *cert_usage, *selector, *matching_type; - char *ss; - int n; - - cert_usage = tlsa_cert_usage_to_string(rr->tlsa.cert_usage); - selector = tlsa_selector_to_string(rr->tlsa.selector); - matching_type = tlsa_matching_type_to_string(rr->tlsa.matching_type); - - r = asprintf(&s, "%s %u %u %u %n", - k, - rr->tlsa.cert_usage, - rr->tlsa.selector, - rr->tlsa.matching_type, - &n); - if (r < 0) - return NULL; - - r = base64_append(&s, n, - rr->tlsa.data, rr->tlsa.data_size, - 8, columns()); - if (r < 0) - return NULL; - - r = asprintf(&ss, "%s\n" - "%*s-- Cert. usage: %s\n" - "%*s-- Selector: %s\n" - "%*s-- Matching type: %s", - s, - n - 6, "", cert_usage, - n - 6, "", selector, - n - 6, "", matching_type); - if (r < 0) - return NULL; - free(s); - s = ss; - - break; - } - - case DNS_TYPE_OPENPGPKEY: { - int n; - - r = asprintf(&s, "%s %n", - k, - &n); - if (r < 0) - return NULL; - - r = base64_append(&s, n, - rr->generic.data, rr->generic.data_size, - 8, columns()); - if (r < 0) - return NULL; - break; - } - - default: - t = hexmem(rr->generic.data, rr->generic.data_size); - if (!t) - return NULL; - - /* Format as documented in RFC 3597, Section 5 */ - r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.data_size, t); - if (r < 0) - return NULL; - break; - } - - rr->to_string = s; - return s; -} - -int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) { - - DnsPacket packet = { - .n_ref = 1, - .protocol = DNS_PROTOCOL_DNS, - .on_stack = true, - .refuse_compression = true, - .canonical_form = canonical, - }; - - size_t start, rds; - int r; - - assert(rr); - - /* Generates the RR in wire-format, optionally in the - * canonical form as discussed in the DNSSEC RFC 4034, Section - * 6.2. We allocate a throw-away DnsPacket object on the stack - * here, because we need some book-keeping for memory - * management, and can reuse the DnsPacket serializer, that - * can generate the canonical form, too, but also knows label - * compression and suchlike. */ - - if (rr->wire_format && rr->wire_format_canonical == canonical) - return 0; - - r = dns_packet_append_rr(&packet, rr, &start, &rds); - if (r < 0) - return r; - - assert(start == 0); - assert(packet._data); - - free(rr->wire_format); - rr->wire_format = packet._data; - rr->wire_format_size = packet.size; - rr->wire_format_rdata_offset = rds; - rr->wire_format_canonical = canonical; - - packet._data = NULL; - dns_packet_unref(&packet); - - return 0; -} - -int dns_resource_record_signer(DnsResourceRecord *rr, const char **ret) { - const char *n; - int r; - - assert(rr); - assert(ret); - - /* Returns the RRset's signer, if it is known. */ - - if (rr->n_skip_labels_signer == (unsigned) -1) - return -ENODATA; - - n = DNS_RESOURCE_KEY_NAME(rr->key); - r = dns_name_skip(n, rr->n_skip_labels_signer, &n); - if (r < 0) - return r; - if (r == 0) - return -EINVAL; - - *ret = n; - return 0; -} - -int dns_resource_record_source(DnsResourceRecord *rr, const char **ret) { - const char *n; - int r; - - assert(rr); - assert(ret); - - /* Returns the RRset's synthesizing source, if it is known. */ - - if (rr->n_skip_labels_source == (unsigned) -1) - return -ENODATA; - - n = DNS_RESOURCE_KEY_NAME(rr->key); - r = dns_name_skip(n, rr->n_skip_labels_source, &n); - if (r < 0) - return r; - if (r == 0) - return -EINVAL; - - *ret = n; - return 0; -} - -int dns_resource_record_is_signer(DnsResourceRecord *rr, const char *zone) { - const char *signer; - int r; - - assert(rr); - - r = dns_resource_record_signer(rr, &signer); - if (r < 0) - return r; - - return dns_name_equal(zone, signer); -} - -int dns_resource_record_is_synthetic(DnsResourceRecord *rr) { - int r; - - assert(rr); - - /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */ - - if (rr->n_skip_labels_source == (unsigned) -1) - return -ENODATA; - - if (rr->n_skip_labels_source == 0) - return 0; - - if (rr->n_skip_labels_source > 1) - return 1; - - r = dns_name_startswith(DNS_RESOURCE_KEY_NAME(rr->key), "*"); - if (r < 0) - return r; - - return !r; -} - -static void dns_resource_record_hash_func(const void *i, struct siphash *state) { - const DnsResourceRecord *rr = i; - - assert(rr); - - dns_resource_key_hash_func(rr->key, state); - - switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) { - - case DNS_TYPE_SRV: - siphash24_compress(&rr->srv.priority, sizeof(rr->srv.priority), state); - siphash24_compress(&rr->srv.weight, sizeof(rr->srv.weight), state); - siphash24_compress(&rr->srv.port, sizeof(rr->srv.port), state); - dns_name_hash_func(rr->srv.name, state); - break; - - case DNS_TYPE_PTR: - case DNS_TYPE_NS: - case DNS_TYPE_CNAME: - case DNS_TYPE_DNAME: - dns_name_hash_func(rr->ptr.name, state); - break; - - case DNS_TYPE_HINFO: - string_hash_func(rr->hinfo.cpu, state); - string_hash_func(rr->hinfo.os, state); - break; - - case DNS_TYPE_TXT: - case DNS_TYPE_SPF: { - DnsTxtItem *j; - - LIST_FOREACH(items, j, rr->txt.items) { - siphash24_compress(j->data, j->length, state); - - /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab" - * followed by "". */ - siphash24_compress_byte(0, state); - } - break; - } - - case DNS_TYPE_A: - siphash24_compress(&rr->a.in_addr, sizeof(rr->a.in_addr), state); - break; - - case DNS_TYPE_AAAA: - siphash24_compress(&rr->aaaa.in6_addr, sizeof(rr->aaaa.in6_addr), state); - break; - - case DNS_TYPE_SOA: - dns_name_hash_func(rr->soa.mname, state); - dns_name_hash_func(rr->soa.rname, state); - siphash24_compress(&rr->soa.serial, sizeof(rr->soa.serial), state); - siphash24_compress(&rr->soa.refresh, sizeof(rr->soa.refresh), state); - siphash24_compress(&rr->soa.retry, sizeof(rr->soa.retry), state); - siphash24_compress(&rr->soa.expire, sizeof(rr->soa.expire), state); - siphash24_compress(&rr->soa.minimum, sizeof(rr->soa.minimum), state); - break; - - case DNS_TYPE_MX: - siphash24_compress(&rr->mx.priority, sizeof(rr->mx.priority), state); - dns_name_hash_func(rr->mx.exchange, state); - break; - - case DNS_TYPE_LOC: - siphash24_compress(&rr->loc.version, sizeof(rr->loc.version), state); - siphash24_compress(&rr->loc.size, sizeof(rr->loc.size), state); - siphash24_compress(&rr->loc.horiz_pre, sizeof(rr->loc.horiz_pre), state); - siphash24_compress(&rr->loc.vert_pre, sizeof(rr->loc.vert_pre), state); - siphash24_compress(&rr->loc.latitude, sizeof(rr->loc.latitude), state); - siphash24_compress(&rr->loc.longitude, sizeof(rr->loc.longitude), state); - siphash24_compress(&rr->loc.altitude, sizeof(rr->loc.altitude), state); - break; - - case DNS_TYPE_SSHFP: - siphash24_compress(&rr->sshfp.algorithm, sizeof(rr->sshfp.algorithm), state); - siphash24_compress(&rr->sshfp.fptype, sizeof(rr->sshfp.fptype), state); - siphash24_compress(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, state); - break; - - case DNS_TYPE_DNSKEY: - siphash24_compress(&rr->dnskey.flags, sizeof(rr->dnskey.flags), state); - siphash24_compress(&rr->dnskey.protocol, sizeof(rr->dnskey.protocol), state); - siphash24_compress(&rr->dnskey.algorithm, sizeof(rr->dnskey.algorithm), state); - siphash24_compress(rr->dnskey.key, rr->dnskey.key_size, state); - break; - - case DNS_TYPE_RRSIG: - siphash24_compress(&rr->rrsig.type_covered, sizeof(rr->rrsig.type_covered), state); - siphash24_compress(&rr->rrsig.algorithm, sizeof(rr->rrsig.algorithm), state); - siphash24_compress(&rr->rrsig.labels, sizeof(rr->rrsig.labels), state); - siphash24_compress(&rr->rrsig.original_ttl, sizeof(rr->rrsig.original_ttl), state); - siphash24_compress(&rr->rrsig.expiration, sizeof(rr->rrsig.expiration), state); - siphash24_compress(&rr->rrsig.inception, sizeof(rr->rrsig.inception), state); - siphash24_compress(&rr->rrsig.key_tag, sizeof(rr->rrsig.key_tag), state); - dns_name_hash_func(rr->rrsig.signer, state); - siphash24_compress(rr->rrsig.signature, rr->rrsig.signature_size, state); - break; - - case DNS_TYPE_NSEC: - dns_name_hash_func(rr->nsec.next_domain_name, state); - /* FIXME: we leave out the type bitmap here. Hash - * would be better if we'd take it into account - * too. */ - break; - - case DNS_TYPE_DS: - siphash24_compress(&rr->ds.key_tag, sizeof(rr->ds.key_tag), state); - siphash24_compress(&rr->ds.algorithm, sizeof(rr->ds.algorithm), state); - siphash24_compress(&rr->ds.digest_type, sizeof(rr->ds.digest_type), state); - siphash24_compress(rr->ds.digest, rr->ds.digest_size, state); - break; - - case DNS_TYPE_NSEC3: - siphash24_compress(&rr->nsec3.algorithm, sizeof(rr->nsec3.algorithm), state); - siphash24_compress(&rr->nsec3.flags, sizeof(rr->nsec3.flags), state); - siphash24_compress(&rr->nsec3.iterations, sizeof(rr->nsec3.iterations), state); - siphash24_compress(rr->nsec3.salt, rr->nsec3.salt_size, state); - siphash24_compress(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, state); - /* FIXME: We leave the bitmaps out */ - break; - - case DNS_TYPE_TLSA: - siphash24_compress(&rr->tlsa.cert_usage, sizeof(rr->tlsa.cert_usage), state); - siphash24_compress(&rr->tlsa.selector, sizeof(rr->tlsa.selector), state); - siphash24_compress(&rr->tlsa.matching_type, sizeof(rr->tlsa.matching_type), state); - siphash24_compress(&rr->tlsa.data, rr->tlsa.data_size, state); - break; - - case DNS_TYPE_OPENPGPKEY: - default: - siphash24_compress(rr->generic.data, rr->generic.data_size, state); - break; - } -} - -static int dns_resource_record_compare_func(const void *a, const void *b) { - const DnsResourceRecord *x = a, *y = b; - int ret; - - ret = dns_resource_key_compare_func(x->key, y->key); - if (ret != 0) - return ret; - - if (dns_resource_record_equal(x, y)) - return 0; - - /* This is a bit dirty, we don't implement proper ordering, but - * the hashtable doesn't need ordering anyway, hence we don't - * care. */ - return x < y ? -1 : 1; -} - -const struct hash_ops dns_resource_record_hash_ops = { - .hash = dns_resource_record_hash_func, - .compare = dns_resource_record_compare_func, -}; - -DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) { - DnsTxtItem *n; - - if (!i) - return NULL; - - n = i->items_next; - - free(i); - return dns_txt_item_free_all(n); -} - -bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) { - - if (a == b) - return true; - - if (!a != !b) - return false; - - if (!a) - return true; - - if (a->length != b->length) - return false; - - if (memcmp(a->data, b->data, a->length) != 0) - return false; - - return dns_txt_item_equal(a->items_next, b->items_next); -} - -static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = { - /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */ - [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5", - [DNSSEC_ALGORITHM_DH] = "DH", - [DNSSEC_ALGORITHM_DSA] = "DSA", - [DNSSEC_ALGORITHM_ECC] = "ECC", - [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1", - [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1", - [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1", - [DNSSEC_ALGORITHM_RSASHA256] = "RSASHA256", - [DNSSEC_ALGORITHM_RSASHA512] = "RSASHA512", - [DNSSEC_ALGORITHM_ECC_GOST] = "ECC-GOST", - [DNSSEC_ALGORITHM_ECDSAP256SHA256] = "ECDSAP256SHA256", - [DNSSEC_ALGORITHM_ECDSAP384SHA384] = "ECDSAP384SHA384", - [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT", - [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS", - [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID", -}; -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm, int, 255); - -static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = { - /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */ - [DNSSEC_DIGEST_SHA1] = "SHA-1", - [DNSSEC_DIGEST_SHA256] = "SHA-256", - [DNSSEC_DIGEST_GOST_R_34_11_94] = "GOST_R_34.11-94", - [DNSSEC_DIGEST_SHA384] = "SHA-384", -}; -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest, int, 255); |