Systemd/src/resolve/resolved-dns-rr.c

1821 lines
60 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <math.h>
#include "alloc-util.h"
2015-06-02 20:49:43 +02:00
#include "dns-domain.h"
#include "dns-type.h"
2016-01-31 22:21:00 +01:00
#include "escape.h"
#include "hexdecoct.h"
#include "memory-util.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"
resolved: add alignment to base64 We try to fit the lengthy key data into available space. If the other fields take less than half of the available columns, we use align everything in the remaining columns. Otherwise, we put everything after a newline, indented with 8 spaces. This is similar to dig and other tools do. $ COLUMNS=78 ./systemd-resolve -t any . . IN SOA a.root-servers.net nstld.verisign-grs.com 2016012701 1800 900 604800 86400 . IN RRSIG SOA RSASHA256 0 86400 20160206170000 20160127160000 54549 S1uhUoBAReAFi5wH/KczVDgwLb+B9Zp57dSYj9aX4XxBhKuzccIducpg0wWXhjCRAWuzY fQ/J2anm4+C4BLUTdlytPIemd42SUffQk2WGuuukI8e67nkrNF3WFtoeXQ4OchsyO24t2 rxi682Zo9ViqmXZ+MSsjWKt1jdem4noaY= . IN NS h.root-servers.net . IN NS k.root-servers.net . IN NS e.root-servers.net . IN NS c.root-servers.net . IN NS b.root-servers.net . IN NS g.root-servers.net . IN NS d.root-servers.net . IN NS f.root-servers.net . IN NS i.root-servers.net . IN NS j.root-servers.net . IN NS m.root-servers.net . IN NS a.root-servers.net . IN NS l.root-servers.net . IN RRSIG NS RSASHA256 0 518400 20160206170000 20160127160000 54549 rxhmTVKUgs72G3VzL+1JRuD0nGLIrPM+ISfmUx0eYUH5wZD5XMu2X+8PfkAsEQT1dziPs ac+zK1YZPbNgr3yGI5H/wEbK8S7DmlvO+/I9WKTLp/Zxn3yncvnTOdjFMZxkAqHbjVOm+ BFz7RjQuvCQlEJX4PQBFphgEnkiOnmMdI= . IN NSEC aaa ( NS SOA RRSIG NSEC DNSKEY ) . IN RRSIG NSEC RSASHA256 0 86400 20160206170000 20160127160000 54549 HY49/nGkUJJP1zLmH33MIKnkNH33jQ7bsAHE9itEjvC4wfAzgq8+Oh9fjYav1R1GDeJ2Z HOu3Z2uDRif10R8RsmZbxyZXJs7eHui9KcAMot1U4uKCCooC/5GImf+oUDbvaraUCMQRU D3mUzoa0BGWfxgZEDqZ55raVFT/olEgG8= . IN DNSKEY 257 3 RSASHA256 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0 O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0 NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL4 96M/QZxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1ap AzvN9dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6 dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ2 5AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1 ihz0= . IN DNSKEY 256 3 RSASHA256 AwEAAbr/RV0stAWYbmKOldjShp4AOQGOyY3ATI1NUpP4X1qBs 6lsXpc+1ABgv6zkg02IktjZrHnmD0HsElu3wqXMrT5KL1W7Sp mg0Pou9WZ8QttdTKXwrVXrASsaGI2z/pLBSnK8EdzqUrTVxY4 TEGZtxV519isM06CCMihxTn5cfFBF . IN RRSIG DNSKEY RSASHA256 0 172800 20160204235959 20160121000000 19036 XYewrVdYKRDfZptAATwT+W4zng04riExV36+z04kok09W0RmOtDlQrlrwHLlD2iN/zYpg EqGgDF5T2xlrQdNpn+PFHhypHM7NQAgLTrwmiw6mGbV0bsZN3rhFxHwW7QVUFAvo9eNVu INrjm+sArwxq3DnPkmA+3K4ikKD2iiT/jT91VYr9SHFqXXURccLjI+nmaE7m31hXcirX/ r5i3J+B4Fx4415IavSD72r7cmruocnCVjcp+ZAUKeMyW+RwigzevLz3oEcCZ4nrTpGLEj wFaVePYoP+rfdmfLfTdmkkm4APRJa2My3XOdGFlgNS1pW1pH4az5LapLE2vMO7p1aQ== -- Information acquired via protocol DNS in 14.4ms. -- Data is authenticated: no
2014-08-05 00:59:31 +02:00
#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);
2016-10-17 00:28:30 +02:00
if (!k)
return mfree(destination);
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, 0, &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 = new(DnsResourceKey, 1);
if (!k)
return NULL;
*k = (DnsResourceKey) {
.n_ref = 1,
.class = class,
.type = type,
._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;
}
const char* dns_resource_key_name(const DnsResourceKey *key) {
const char *name;
if (!key)
return NULL;
if (key->_name)
name = key->_name;
else
name = (char*) key + sizeof(DnsResourceKey);
if (dns_name_is_root(name))
return ".";
else
return name;
}
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);
}
bool dns_resource_key_is_dnssd_ptr(const DnsResourceKey *key) {
assert(key);
/* Check if this is a PTR resource key used in
Service Instance Enumeration as described in RFC6763 p4.1. */
if (key->type != DNS_TYPE_PTR)
return false;
return dns_name_endswith(dns_resource_key_name(key), "_tcp.local") ||
dns_name_endswith(dns_resource_key_name(key), "_udp.local");
}
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, 0, &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, 0, &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;
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled This adds initial support for validating RRSIG/DNSKEY/DS chains when doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not implemented yet. With this change DnsTransaction objects will generate additional DnsTransaction objects when looking for DNSKEY or DS RRs to validate an RRSIG on a response. DnsTransaction objects are thus created for three reasons now: 1) Because a user asked for something to be resolved, i.e. requested by a DnsQuery/DnsQueryCandidate object. 2) As result of LLMNR RR probing, requested by a DnsZoneItem. 3) Because another DnsTransaction requires the requested RRs for validation of its own response. DnsTransactions are shared between all these users, and are GC automatically as soon as all of these users don't need a specific transaction anymore. To unify the handling of these three reasons for existance for a DnsTransaction, a new common naming is introduced: each DnsTransaction now tracks its "owners" via a Set* object named "notify_xyz", containing all owners to notify on completion. A new DnsTransaction state is introduced called "VALIDATING" that is entered after a response has been receieved which needs to be validated, as long as we are still waiting for the DNSKEY/DS RRs from other DnsTransactions. This patch will request the DNSKEY/DS RRs bottom-up, and then validate them top-down. Caching of RRs is now only done after verification, so that the cache is not poisoned with known invalid data. The "DnsAnswer" object gained a substantial number of new calls, since we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
}
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)
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled This adds initial support for validating RRSIG/DNSKEY/DS chains when doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not implemented yet. With this change DnsTransaction objects will generate additional DnsTransaction objects when looking for DNSKEY or DS RRs to validate an RRSIG on a response. DnsTransaction objects are thus created for three reasons now: 1) Because a user asked for something to be resolved, i.e. requested by a DnsQuery/DnsQueryCandidate object. 2) As result of LLMNR RR probing, requested by a DnsZoneItem. 3) Because another DnsTransaction requires the requested RRs for validation of its own response. DnsTransactions are shared between all these users, and are GC automatically as soon as all of these users don't need a specific transaction anymore. To unify the handling of these three reasons for existance for a DnsTransaction, a new common naming is introduced: each DnsTransaction now tracks its "owners" via a Set* object named "notify_xyz", containing all owners to notify on completion. A new DnsTransaction state is introduced called "VALIDATING" that is entered after a response has been receieved which needs to be validated, as long as we are still waiting for the DNSKEY/DS RRs from other DnsTransactions. This patch will request the DNSKEY/DS RRs bottom-up, and then validate them top-down. Caching of RRs is now only done after verification, so that the cache is not poisoned with known invalid data. The "DnsAnswer" object gained a substantial number of new calls, since we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
return 0;
resolved: chase DNSKEY/DS RRs when doing look-ups with DNSSEC enabled This adds initial support for validating RRSIG/DNSKEY/DS chains when doing lookups. Proof-of-non-existance, or proof-of-unsigned-zones is not implemented yet. With this change DnsTransaction objects will generate additional DnsTransaction objects when looking for DNSKEY or DS RRs to validate an RRSIG on a response. DnsTransaction objects are thus created for three reasons now: 1) Because a user asked for something to be resolved, i.e. requested by a DnsQuery/DnsQueryCandidate object. 2) As result of LLMNR RR probing, requested by a DnsZoneItem. 3) Because another DnsTransaction requires the requested RRs for validation of its own response. DnsTransactions are shared between all these users, and are GC automatically as soon as all of these users don't need a specific transaction anymore. To unify the handling of these three reasons for existance for a DnsTransaction, a new common naming is introduced: each DnsTransaction now tracks its "owners" via a Set* object named "notify_xyz", containing all owners to notify on completion. A new DnsTransaction state is introduced called "VALIDATING" that is entered after a response has been receieved which needs to be validated, as long as we are still waiting for the DNSKEY/DS RRs from other DnsTransactions. This patch will request the DNSKEY/DS RRs bottom-up, and then validate them top-down. Caching of RRs is now only done after verification, so that the cache is not poisoned with known invalid data. The "DnsAnswer" object gained a substantial number of new calls, since we need to add/remove RRs to it dynamically now.
2015-12-09 18:13:16 +01:00
if (soa->type != DNS_TYPE_SOA)
return 0;
return dns_name_endswith(dns_resource_key_name(key), dns_resource_key_name(soa));
}
2018-11-27 14:25:20 +01:00
static void dns_resource_key_hash_func(const DnsResourceKey *k, struct siphash *state) {
assert(k);
2014-07-17 19:38:37 +02:00
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);
2014-07-17 19:38:37 +02:00
}
2018-11-27 14:25:20 +01:00
static int dns_resource_key_compare_func(const DnsResourceKey *x, const DnsResourceKey *y) {
int r;
2014-07-17 19:38:37 +02:00
r = dns_name_compare_func(dns_resource_key_name(x), dns_resource_key_name(y));
if (r != 0)
return r;
2014-07-17 19:38:37 +02:00
r = CMP(x->type, y->type);
if (r != 0)
return r;
2014-07-17 19:38:37 +02:00
return CMP(x->class, y->class);
2014-07-17 19:38:37 +02:00
}
2018-11-27 14:25:20 +01:00
DEFINE_HASH_OPS(dns_resource_key_hash_ops, DnsResourceKey, dns_resource_key_hash_func, dns_resource_key_compare_func);
char* dns_resource_key_to_string(const DnsResourceKey *key, char *buf, size_t buf_size) {
const char *c, *t;
char *ans = buf;
/* 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);
t = dns_type_to_string(key->type);
snprintf(buf, buf_size, "%s %s%s%.0u %s%s%.0u",
dns_resource_key_name(key),
strempty(c), c ? "" : "CLASS", c ? 0 : key->class,
2018-06-19 14:01:57 +02:00
strempty(t), t ? "" : "TYPE", t ? 0 : key->type);
return ans;
}
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 = new(DnsResourceRecord, 1);
if (!rr)
return NULL;
*rr = (DnsResourceRecord) {
.n_ref = 1,
.key = dns_resource_key_ref(key),
.expiry = USEC_INFINITY,
.n_skip_labels_signer = (unsigned) -1,
.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);
}
static DnsResourceRecord* dns_resource_record_free(DnsResourceRecord *rr) {
assert(rr);
if (rr->key) {
2014-08-01 03:47:51 +02:00
switch(rr->key->type) {
2014-07-31 18:23:00 +02:00
case DNS_TYPE_SRV:
free(rr->srv.name);
break;
2014-08-01 03:47:51 +02:00
case DNS_TYPE_PTR:
case DNS_TYPE_NS:
case DNS_TYPE_CNAME:
2014-07-31 18:02:24 +02:00
case DNS_TYPE_DNAME:
free(rr->ptr.name);
2014-08-01 03:47:51 +02:00
break;
2014-07-31 18:23:00 +02:00
2014-08-01 03:47:51 +02:00
case DNS_TYPE_HINFO:
free(rr->hinfo.cpu);
free(rr->hinfo.os);
2014-08-01 03:47:51 +02:00
break;
2014-07-31 18:23:00 +02:00
2014-08-01 03:47:51 +02:00
case DNS_TYPE_TXT:
2014-07-31 18:23:00 +02:00
case DNS_TYPE_SPF:
dns_txt_item_free_all(rr->txt.items);
2014-08-01 03:47:51 +02:00
break;
2014-07-31 18:23:00 +02:00
2014-08-01 03:47:51 +02:00
case DNS_TYPE_SOA:
2014-07-23 00:57:25 +02:00
free(rr->soa.mname);
free(rr->soa.rname);
2014-08-01 03:47:51 +02:00
break;
2014-07-31 18:23:00 +02:00
2014-08-01 03:47:51 +02:00
case DNS_TYPE_MX:
2014-08-01 03:06:00 +02:00
free(rr->mx.exchange);
2014-08-01 03:47:51 +02:00
break;
2014-07-31 18:23:00 +02:00
case DNS_TYPE_DS:
free(rr->ds.digest);
break;
2014-07-31 18:41:41 +02:00
case DNS_TYPE_SSHFP:
free(rr->sshfp.fingerprint);
2014-07-31 18:41:41 +02:00
break;
2014-08-03 22:05:41 +02:00
case DNS_TYPE_DNSKEY:
free(rr->dnskey.key);
break;
2014-08-04 00:17:22 +02:00
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:
2014-08-01 03:47:51 +02:00
case DNS_TYPE_A:
case DNS_TYPE_AAAA:
break;
2014-07-31 18:23:00 +02:00
2015-02-02 01:17:24 +01:00
case DNS_TYPE_TLSA:
free(rr->tlsa.data);
break;
2016-01-31 22:21:00 +01:00
case DNS_TYPE_CAA:
free(rr->caa.tag);
free(rr->caa.value);
break;
2015-02-02 02:54:15 +01:00
case DNS_TYPE_OPENPGPKEY:
2014-08-01 03:47:51 +02:00
default:
if (!rr->unparsable)
free(rr->generic.data);
2014-08-01 03:47:51 +02:00
}
2014-07-17 19:38:37 +02:00
if (rr->unparsable)
free(rr->generic.data);
free(rr->wire_format);
dns_resource_key_unref(rr->key);
}
2014-07-17 19:38:37 +02:00
free(rr->to_string);
2016-10-17 00:28:30 +02:00
return mfree(rr);
2014-07-17 19:38:37 +02:00
}
DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsResourceRecord, dns_resource_record, dns_resource_record_free);
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 = TAKE_PTR(rr);
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_safe((a).field, (b).field, (a).field ## _size) == 0)
int dns_resource_record_payload_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
2014-07-17 19:38:37 +02:00
int r;
/* Check if a and b are the same, but don't look at their keys */
2014-07-17 19:38:37 +02:00
if (a->unparsable != b->unparsable)
return 0;
switch (a->unparsable ? _DNS_TYPE_INVALID : a->key->type) {
2014-07-31 18:23:00 +02:00
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:
2014-07-31 18:02:24 +02:00
case DNS_TYPE_DNAME:
2014-07-17 19:38:37 +02:00
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);
2014-08-01 03:47:51 +02:00
case DNS_TYPE_SPF: /* exactly the same as TXT */
case DNS_TYPE_TXT:
return dns_txt_item_equal(a->txt.items, b->txt.items);
2014-08-01 03:36:58 +02:00
case DNS_TYPE_A:
2014-07-17 19:38:37 +02:00
return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
case DNS_TYPE_AAAA:
2014-07-17 19:38:37 +02:00
return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
case DNS_TYPE_SOA:
2014-07-23 00:57:25 +02:00
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;
2014-07-31 18:23:00 +02:00
2014-08-01 03:06:00 +02:00
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);
2014-07-31 18:41:41 +02:00
case DNS_TYPE_SSHFP:
return a->sshfp.algorithm == b->sshfp.algorithm &&
a->sshfp.fptype == b->sshfp.fptype &&
FIELD_EQUAL(a->sshfp, b->sshfp, fingerprint);
2014-07-31 18:41:41 +02:00
2014-08-03 22:05:41 +02:00
case DNS_TYPE_DNSKEY:
return a->dnskey.flags == b->dnskey.flags &&
a->dnskey.protocol == b->dnskey.protocol &&
2014-08-03 22:05:41 +02:00
a->dnskey.algorithm == b->dnskey.algorithm &&
FIELD_EQUAL(a->dnskey, b->dnskey, key);
2014-08-03 22:05:41 +02:00
2014-08-04 00:17:22 +02:00
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);
2014-08-04 00:17:22 +02:00
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);
2015-02-02 01:17:24 +01:00
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);
2015-02-02 01:17:24 +01:00
2016-01-31 22:21:00 +01:00
case DNS_TYPE_CAA:
return a->caa.flags == b->caa.flags &&
streq(a->caa.tag, b->caa.tag) &&
FIELD_EQUAL(a->caa, b->caa, value);
case DNS_TYPE_OPENPGPKEY:
default:
return FIELD_EQUAL(a->generic, b->generic, data);
}
2014-07-17 19:38:37 +02:00
}
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;
return dns_resource_record_payload_equal(a, b);
}
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;
unsigned type;
int r;
BITMAP_FOREACH(type, types) {
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, " )");
}
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 *t = NULL;
char *s, k[DNS_RESOURCE_KEY_STRING_MAX];
int r;
2014-07-17 19:38:37 +02:00
assert(rr);
2014-07-17 19:38:37 +02:00
if (rr->to_string)
return rr->to_string;
dns_resource_key_to_string(rr->key, k, sizeof(k));
2014-07-17 19:38:37 +02:00
switch (rr->unparsable ? _DNS_TYPE_INVALID : rr->key->type) {
2014-07-17 19:38:37 +02:00
2014-07-31 18:23:00 +02:00
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;
2014-07-31 18:23:00 +02:00
break;
case DNS_TYPE_PTR:
case DNS_TYPE_NS:
case DNS_TYPE_CNAME:
2014-07-31 18:02:24 +02:00
case DNS_TYPE_DNAME:
s = strjoin(k, " ", rr->ptr.name);
if (!s)
return NULL;
2014-07-17 19:38:37 +02:00
break;
2014-07-17 19:38:37 +02:00
case DNS_TYPE_HINFO:
s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os);
if (!s)
return NULL;
break;
2014-07-17 19:38:37 +02:00
2014-08-01 03:47:51 +02:00
case DNS_TYPE_SPF: /* exactly the same as TXT */
2014-08-03 22:05:41 +02:00
case DNS_TYPE_TXT:
t = format_txt(rr->txt.items);
2014-08-01 03:36:58 +02:00
if (!t)
return NULL;
2014-08-01 03:36:58 +02:00
s = strjoin(k, " ", t);
2014-08-01 03:36:58 +02:00
if (!s)
return NULL;
2014-08-01 03:36:58 +02:00
break;
case DNS_TYPE_A: {
_cleanup_free_ char *x = NULL;
2014-07-17 19:38:37 +02:00
r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
if (r < 0)
return NULL;
2014-07-17 19:38:37 +02:00
s = strjoin(k, " ", x);
if (!s)
return NULL;
break;
}
2014-07-17 19:38:37 +02:00
2014-08-03 22:05:41 +02:00
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;
2014-07-17 19:38:37 +02:00
s = strjoin(k, " ", t);
if (!s)
return NULL;
break;
2014-07-17 19:38:37 +02:00
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;
2014-08-01 03:06:00 +02:00
case DNS_TYPE_MX:
r = asprintf(&s, "%s %u %s",
k,
rr->mx.priority,
rr->mx.exchange);
if (r < 0)
return NULL;
2014-08-01 03:06:00 +02:00
break;
2014-08-03 22:05:41 +02:00
case DNS_TYPE_LOC:
assert(rr->loc.version == 0);
2014-08-03 22:05:41 +02:00
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);
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;
2014-08-03 22:05:41 +02:00
case DNS_TYPE_SSHFP:
t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
2014-08-03 22:05:41 +02:00
if (!t)
return NULL;
2014-07-31 18:41:41 +02:00
r = asprintf(&s, "%s %u %u %s",
k,
rr->sshfp.algorithm,
rr->sshfp.fptype,
2014-08-03 22:05:41 +02:00
t);
2014-07-31 18:41:41 +02:00
if (r < 0)
return NULL;
2014-07-31 18:41:41 +02:00
break;
case DNS_TYPE_DNSKEY: {
_cleanup_free_ char *alg = NULL;
char *ss;
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 %u %u %s",
2014-08-03 22:05:41 +02:00
k,
rr->dnskey.flags,
rr->dnskey.protocol,
alg);
2014-08-03 22:05:41 +02:00
if (r < 0)
return NULL;
resolved: add alignment to base64 We try to fit the lengthy key data into available space. If the other fields take less than half of the available columns, we use align everything in the remaining columns. Otherwise, we put everything after a newline, indented with 8 spaces. This is similar to dig and other tools do. $ COLUMNS=78 ./systemd-resolve -t any . . IN SOA a.root-servers.net nstld.verisign-grs.com 2016012701 1800 900 604800 86400 . IN RRSIG SOA RSASHA256 0 86400 20160206170000 20160127160000 54549 S1uhUoBAReAFi5wH/KczVDgwLb+B9Zp57dSYj9aX4XxBhKuzccIducpg0wWXhjCRAWuzY fQ/J2anm4+C4BLUTdlytPIemd42SUffQk2WGuuukI8e67nkrNF3WFtoeXQ4OchsyO24t2 rxi682Zo9ViqmXZ+MSsjWKt1jdem4noaY= . IN NS h.root-servers.net . IN NS k.root-servers.net . IN NS e.root-servers.net . IN NS c.root-servers.net . IN NS b.root-servers.net . IN NS g.root-servers.net . IN NS d.root-servers.net . IN NS f.root-servers.net . IN NS i.root-servers.net . IN NS j.root-servers.net . IN NS m.root-servers.net . IN NS a.root-servers.net . IN NS l.root-servers.net . IN RRSIG NS RSASHA256 0 518400 20160206170000 20160127160000 54549 rxhmTVKUgs72G3VzL+1JRuD0nGLIrPM+ISfmUx0eYUH5wZD5XMu2X+8PfkAsEQT1dziPs ac+zK1YZPbNgr3yGI5H/wEbK8S7DmlvO+/I9WKTLp/Zxn3yncvnTOdjFMZxkAqHbjVOm+ BFz7RjQuvCQlEJX4PQBFphgEnkiOnmMdI= . IN NSEC aaa ( NS SOA RRSIG NSEC DNSKEY ) . IN RRSIG NSEC RSASHA256 0 86400 20160206170000 20160127160000 54549 HY49/nGkUJJP1zLmH33MIKnkNH33jQ7bsAHE9itEjvC4wfAzgq8+Oh9fjYav1R1GDeJ2Z HOu3Z2uDRif10R8RsmZbxyZXJs7eHui9KcAMot1U4uKCCooC/5GImf+oUDbvaraUCMQRU D3mUzoa0BGWfxgZEDqZ55raVFT/olEgG8= . IN DNSKEY 257 3 RSASHA256 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0 O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0 NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL4 96M/QZxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1ap AzvN9dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6 dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ2 5AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1 ihz0= . IN DNSKEY 256 3 RSASHA256 AwEAAbr/RV0stAWYbmKOldjShp4AOQGOyY3ATI1NUpP4X1qBs 6lsXpc+1ABgv6zkg02IktjZrHnmD0HsElu3wqXMrT5KL1W7Sp mg0Pou9WZ8QttdTKXwrVXrASsaGI2z/pLBSnK8EdzqUrTVxY4 TEGZtxV519isM06CCMihxTn5cfFBF . IN RRSIG DNSKEY RSASHA256 0 172800 20160204235959 20160121000000 19036 XYewrVdYKRDfZptAATwT+W4zng04riExV36+z04kok09W0RmOtDlQrlrwHLlD2iN/zYpg EqGgDF5T2xlrQdNpn+PFHhypHM7NQAgLTrwmiw6mGbV0bsZN3rhFxHwW7QVUFAvo9eNVu INrjm+sArwxq3DnPkmA+3K4ikKD2iiT/jT91VYr9SHFqXXURccLjI+nmaE7m31hXcirX/ r5i3J+B4Fx4415IavSD72r7cmruocnCVjcp+ZAUKeMyW+RwigzevLz3oEcCZ4nrTpGLEj wFaVePYoP+rfdmfLfTdmkkm4APRJa2My3XOdGFlgNS1pW1pH4az5LapLE2vMO7p1aQ== -- Information acquired via protocol DNS in 14.4ms. -- Data is authenticated: no
2014-08-05 00:59:31 +02:00
r = base64_append(&s, r,
resolved: add alignment to base64 We try to fit the lengthy key data into available space. If the other fields take less than half of the available columns, we use align everything in the remaining columns. Otherwise, we put everything after a newline, indented with 8 spaces. This is similar to dig and other tools do. $ COLUMNS=78 ./systemd-resolve -t any . . IN SOA a.root-servers.net nstld.verisign-grs.com 2016012701 1800 900 604800 86400 . IN RRSIG SOA RSASHA256 0 86400 20160206170000 20160127160000 54549 S1uhUoBAReAFi5wH/KczVDgwLb+B9Zp57dSYj9aX4XxBhKuzccIducpg0wWXhjCRAWuzY fQ/J2anm4+C4BLUTdlytPIemd42SUffQk2WGuuukI8e67nkrNF3WFtoeXQ4OchsyO24t2 rxi682Zo9ViqmXZ+MSsjWKt1jdem4noaY= . IN NS h.root-servers.net . IN NS k.root-servers.net . IN NS e.root-servers.net . IN NS c.root-servers.net . IN NS b.root-servers.net . IN NS g.root-servers.net . IN NS d.root-servers.net . IN NS f.root-servers.net . IN NS i.root-servers.net . IN NS j.root-servers.net . IN NS m.root-servers.net . IN NS a.root-servers.net . IN NS l.root-servers.net . IN RRSIG NS RSASHA256 0 518400 20160206170000 20160127160000 54549 rxhmTVKUgs72G3VzL+1JRuD0nGLIrPM+ISfmUx0eYUH5wZD5XMu2X+8PfkAsEQT1dziPs ac+zK1YZPbNgr3yGI5H/wEbK8S7DmlvO+/I9WKTLp/Zxn3yncvnTOdjFMZxkAqHbjVOm+ BFz7RjQuvCQlEJX4PQBFphgEnkiOnmMdI= . IN NSEC aaa ( NS SOA RRSIG NSEC DNSKEY ) . IN RRSIG NSEC RSASHA256 0 86400 20160206170000 20160127160000 54549 HY49/nGkUJJP1zLmH33MIKnkNH33jQ7bsAHE9itEjvC4wfAzgq8+Oh9fjYav1R1GDeJ2Z HOu3Z2uDRif10R8RsmZbxyZXJs7eHui9KcAMot1U4uKCCooC/5GImf+oUDbvaraUCMQRU D3mUzoa0BGWfxgZEDqZ55raVFT/olEgG8= . IN DNSKEY 257 3 RSASHA256 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0 O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0 NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL4 96M/QZxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1ap AzvN9dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6 dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ2 5AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1 ihz0= . IN DNSKEY 256 3 RSASHA256 AwEAAbr/RV0stAWYbmKOldjShp4AOQGOyY3ATI1NUpP4X1qBs 6lsXpc+1ABgv6zkg02IktjZrHnmD0HsElu3wqXMrT5KL1W7Sp mg0Pou9WZ8QttdTKXwrVXrASsaGI2z/pLBSnK8EdzqUrTVxY4 TEGZtxV519isM06CCMihxTn5cfFBF . IN RRSIG DNSKEY RSASHA256 0 172800 20160204235959 20160121000000 19036 XYewrVdYKRDfZptAATwT+W4zng04riExV36+z04kok09W0RmOtDlQrlrwHLlD2iN/zYpg EqGgDF5T2xlrQdNpn+PFHhypHM7NQAgLTrwmiw6mGbV0bsZN3rhFxHwW7QVUFAvo9eNVu INrjm+sArwxq3DnPkmA+3K4ikKD2iiT/jT91VYr9SHFqXXURccLjI+nmaE7m31hXcirX/ r5i3J+B4Fx4415IavSD72r7cmruocnCVjcp+ZAUKeMyW+RwigzevLz3oEcCZ4nrTpGLEj wFaVePYoP+rfdmfLfTdmkkm4APRJa2My3XOdGFlgNS1pW1pH4az5LapLE2vMO7p1aQ== -- Information acquired via protocol DNS in 14.4ms. -- Data is authenticated: no
2014-08-05 00:59:31 +02:00
rr->dnskey.key, rr->dnskey.key_size,
8, columns());
if (r < 0)
return NULL;
r = asprintf(&ss, "%s\n"
" -- Flags:%s%s%s\n"
" -- Key tag: %u",
s,
rr->dnskey.flags & DNSKEY_FLAG_SEP ? " SEP" : "",
rr->dnskey.flags & DNSKEY_FLAG_REVOKE ? " REVOKE" : "",
rr->dnskey.flags & DNSKEY_FLAG_ZONE_KEY ? " ZONE_KEY" : "",
key_tag);
if (r < 0)
return NULL;
free(s);
s = ss;
2014-08-03 22:05:41 +02:00
break;
}
2014-08-04 00:17:22 +02:00
case DNS_TYPE_RRSIG: {
_cleanup_free_ char *alg = NULL;
char expiration[STRLEN("YYYYMMDDHHmmSS") + 1], inception[STRLEN("YYYYMMDDHHmmSS") + 1];
const char *type;
2014-08-04 00:17:22 +02:00
type = dns_type_to_string(rr->rrsig.type_covered);
r = dnssec_algorithm_to_string_alloc(rr->rrsig.algorithm, &alg);
if (r < 0)
return NULL;
2014-08-04 00:17:22 +02:00
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;
2014-08-04 00:17:22 +02:00
/* TYPE?? follows
* http://tools.ietf.org/html/rfc3597#section-5 */
r = asprintf(&s, "%s %s%.*u %s %u %u %s %s %u %s",
2014-08-04 00:17:22 +02:00
k,
type ?: "TYPE",
type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
alg,
2014-08-04 00:17:22 +02:00
rr->rrsig.labels,
rr->rrsig.original_ttl,
expiration,
inception,
2014-08-04 00:17:22 +02:00
rr->rrsig.key_tag,
rr->rrsig.signer);
2014-08-04 00:17:22 +02:00
if (r < 0)
return NULL;
resolved: add alignment to base64 We try to fit the lengthy key data into available space. If the other fields take less than half of the available columns, we use align everything in the remaining columns. Otherwise, we put everything after a newline, indented with 8 spaces. This is similar to dig and other tools do. $ COLUMNS=78 ./systemd-resolve -t any . . IN SOA a.root-servers.net nstld.verisign-grs.com 2016012701 1800 900 604800 86400 . IN RRSIG SOA RSASHA256 0 86400 20160206170000 20160127160000 54549 S1uhUoBAReAFi5wH/KczVDgwLb+B9Zp57dSYj9aX4XxBhKuzccIducpg0wWXhjCRAWuzY fQ/J2anm4+C4BLUTdlytPIemd42SUffQk2WGuuukI8e67nkrNF3WFtoeXQ4OchsyO24t2 rxi682Zo9ViqmXZ+MSsjWKt1jdem4noaY= . IN NS h.root-servers.net . IN NS k.root-servers.net . IN NS e.root-servers.net . IN NS c.root-servers.net . IN NS b.root-servers.net . IN NS g.root-servers.net . IN NS d.root-servers.net . IN NS f.root-servers.net . IN NS i.root-servers.net . IN NS j.root-servers.net . IN NS m.root-servers.net . IN NS a.root-servers.net . IN NS l.root-servers.net . IN RRSIG NS RSASHA256 0 518400 20160206170000 20160127160000 54549 rxhmTVKUgs72G3VzL+1JRuD0nGLIrPM+ISfmUx0eYUH5wZD5XMu2X+8PfkAsEQT1dziPs ac+zK1YZPbNgr3yGI5H/wEbK8S7DmlvO+/I9WKTLp/Zxn3yncvnTOdjFMZxkAqHbjVOm+ BFz7RjQuvCQlEJX4PQBFphgEnkiOnmMdI= . IN NSEC aaa ( NS SOA RRSIG NSEC DNSKEY ) . IN RRSIG NSEC RSASHA256 0 86400 20160206170000 20160127160000 54549 HY49/nGkUJJP1zLmH33MIKnkNH33jQ7bsAHE9itEjvC4wfAzgq8+Oh9fjYav1R1GDeJ2Z HOu3Z2uDRif10R8RsmZbxyZXJs7eHui9KcAMot1U4uKCCooC/5GImf+oUDbvaraUCMQRU D3mUzoa0BGWfxgZEDqZ55raVFT/olEgG8= . IN DNSKEY 257 3 RSASHA256 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0 O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0 NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL4 96M/QZxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1ap AzvN9dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6 dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ2 5AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1 ihz0= . IN DNSKEY 256 3 RSASHA256 AwEAAbr/RV0stAWYbmKOldjShp4AOQGOyY3ATI1NUpP4X1qBs 6lsXpc+1ABgv6zkg02IktjZrHnmD0HsElu3wqXMrT5KL1W7Sp mg0Pou9WZ8QttdTKXwrVXrASsaGI2z/pLBSnK8EdzqUrTVxY4 TEGZtxV519isM06CCMihxTn5cfFBF . IN RRSIG DNSKEY RSASHA256 0 172800 20160204235959 20160121000000 19036 XYewrVdYKRDfZptAATwT+W4zng04riExV36+z04kok09W0RmOtDlQrlrwHLlD2iN/zYpg EqGgDF5T2xlrQdNpn+PFHhypHM7NQAgLTrwmiw6mGbV0bsZN3rhFxHwW7QVUFAvo9eNVu INrjm+sArwxq3DnPkmA+3K4ikKD2iiT/jT91VYr9SHFqXXURccLjI+nmaE7m31hXcirX/ r5i3J+B4Fx4415IavSD72r7cmruocnCVjcp+ZAUKeMyW+RwigzevLz3oEcCZ4nrTpGLEj wFaVePYoP+rfdmfLfTdmkkm4APRJa2My3XOdGFlgNS1pW1pH4az5LapLE2vMO7p1aQ== -- Information acquired via protocol DNS in 14.4ms. -- Data is authenticated: no
2014-08-05 00:59:31 +02:00
r = base64_append(&s, r,
resolved: add alignment to base64 We try to fit the lengthy key data into available space. If the other fields take less than half of the available columns, we use align everything in the remaining columns. Otherwise, we put everything after a newline, indented with 8 spaces. This is similar to dig and other tools do. $ COLUMNS=78 ./systemd-resolve -t any . . IN SOA a.root-servers.net nstld.verisign-grs.com 2016012701 1800 900 604800 86400 . IN RRSIG SOA RSASHA256 0 86400 20160206170000 20160127160000 54549 S1uhUoBAReAFi5wH/KczVDgwLb+B9Zp57dSYj9aX4XxBhKuzccIducpg0wWXhjCRAWuzY fQ/J2anm4+C4BLUTdlytPIemd42SUffQk2WGuuukI8e67nkrNF3WFtoeXQ4OchsyO24t2 rxi682Zo9ViqmXZ+MSsjWKt1jdem4noaY= . IN NS h.root-servers.net . IN NS k.root-servers.net . IN NS e.root-servers.net . IN NS c.root-servers.net . IN NS b.root-servers.net . IN NS g.root-servers.net . IN NS d.root-servers.net . IN NS f.root-servers.net . IN NS i.root-servers.net . IN NS j.root-servers.net . IN NS m.root-servers.net . IN NS a.root-servers.net . IN NS l.root-servers.net . IN RRSIG NS RSASHA256 0 518400 20160206170000 20160127160000 54549 rxhmTVKUgs72G3VzL+1JRuD0nGLIrPM+ISfmUx0eYUH5wZD5XMu2X+8PfkAsEQT1dziPs ac+zK1YZPbNgr3yGI5H/wEbK8S7DmlvO+/I9WKTLp/Zxn3yncvnTOdjFMZxkAqHbjVOm+ BFz7RjQuvCQlEJX4PQBFphgEnkiOnmMdI= . IN NSEC aaa ( NS SOA RRSIG NSEC DNSKEY ) . IN RRSIG NSEC RSASHA256 0 86400 20160206170000 20160127160000 54549 HY49/nGkUJJP1zLmH33MIKnkNH33jQ7bsAHE9itEjvC4wfAzgq8+Oh9fjYav1R1GDeJ2Z HOu3Z2uDRif10R8RsmZbxyZXJs7eHui9KcAMot1U4uKCCooC/5GImf+oUDbvaraUCMQRU D3mUzoa0BGWfxgZEDqZ55raVFT/olEgG8= . IN DNSKEY 257 3 RSASHA256 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0 O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0 NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL4 96M/QZxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1ap AzvN9dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6 dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ2 5AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1 ihz0= . IN DNSKEY 256 3 RSASHA256 AwEAAbr/RV0stAWYbmKOldjShp4AOQGOyY3ATI1NUpP4X1qBs 6lsXpc+1ABgv6zkg02IktjZrHnmD0HsElu3wqXMrT5KL1W7Sp mg0Pou9WZ8QttdTKXwrVXrASsaGI2z/pLBSnK8EdzqUrTVxY4 TEGZtxV519isM06CCMihxTn5cfFBF . IN RRSIG DNSKEY RSASHA256 0 172800 20160204235959 20160121000000 19036 XYewrVdYKRDfZptAATwT+W4zng04riExV36+z04kok09W0RmOtDlQrlrwHLlD2iN/zYpg EqGgDF5T2xlrQdNpn+PFHhypHM7NQAgLTrwmiw6mGbV0bsZN3rhFxHwW7QVUFAvo9eNVu INrjm+sArwxq3DnPkmA+3K4ikKD2iiT/jT91VYr9SHFqXXURccLjI+nmaE7m31hXcirX/ r5i3J+B4Fx4415IavSD72r7cmruocnCVjcp+ZAUKeMyW+RwigzevLz3oEcCZ4nrTpGLEj wFaVePYoP+rfdmfLfTdmkkm4APRJa2My3XOdGFlgNS1pW1pH4az5LapLE2vMO7p1aQ== -- Information acquired via protocol DNS in 14.4ms. -- Data is authenticated: no
2014-08-05 00:59:31 +02:00
rr->rrsig.signature, rr->rrsig.signature_size,
8, columns());
if (r < 0)
return NULL;
2014-08-04 00:17:22 +02:00
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;
}
2015-02-02 01:17:24 +01:00
case DNS_TYPE_TLSA: {
const char *cert_usage, *selector, *matching_type;
2015-02-02 01:17:24 +01:00
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);
t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
if (!t)
2015-02-02 01:17:24 +01:00
return NULL;
r = asprintf(&s,
"%s %u %u %u %s\n"
" -- Cert. usage: %s\n"
" -- Selector: %s\n"
" -- Matching type: %s",
k,
rr->tlsa.cert_usage,
rr->tlsa.selector,
rr->tlsa.matching_type,
t,
cert_usage,
selector,
matching_type);
if (r < 0)
return NULL;
2015-02-02 01:17:24 +01:00
break;
}
2016-01-31 22:21:00 +01:00
case DNS_TYPE_CAA: {
_cleanup_free_ char *value;
value = octescape(rr->caa.value, rr->caa.value_size);
if (!value)
return NULL;
r = asprintf(&s, "%s %u %s \"%s\"%s%s%s%.0u",
2016-01-31 22:21:00 +01:00
k,
rr->caa.flags,
rr->caa.tag,
value,
rr->caa.flags ? "\n -- Flags:" : "",
rr->caa.flags & CAA_FLAG_CRITICAL ? " critical" : "",
rr->caa.flags & ~CAA_FLAG_CRITICAL ? " " : "",
rr->caa.flags & ~CAA_FLAG_CRITICAL);
2016-01-31 22:21:00 +01:00
if (r < 0)
return NULL;
break;
}
2015-02-02 02:54:15 +01:00
case DNS_TYPE_OPENPGPKEY: {
r = asprintf(&s, "%s", k);
2015-02-02 02:54:15 +01:00
if (r < 0)
return NULL;
r = base64_append(&s, r,
rr->generic.data, rr->generic.data_size,
2015-02-02 02:54:15 +01:00
8, columns());
if (r < 0)
return NULL;
break;
}
2014-08-03 22:05:41 +02:00
default:
t = hexmem(rr->generic.data, rr->generic.data_size);
2014-08-03 22:05:41 +02:00
if (!t)
return NULL;
2014-08-03 22:05:41 +02:00
/* 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;
2014-08-03 22:05:41 +02:00
}
rr->to_string = s;
return s;
}
2014-07-17 19:38:37 +02:00
ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out) {
assert(rr);
assert(out);
switch(rr->unparsable ? _DNS_TYPE_INVALID : rr->key->type) {
case DNS_TYPE_SRV:
case DNS_TYPE_PTR:
case DNS_TYPE_NS:
case DNS_TYPE_CNAME:
case DNS_TYPE_DNAME:
case DNS_TYPE_HINFO:
case DNS_TYPE_SPF:
case DNS_TYPE_TXT:
case DNS_TYPE_A:
case DNS_TYPE_AAAA:
case DNS_TYPE_SOA:
case DNS_TYPE_MX:
case DNS_TYPE_LOC:
case DNS_TYPE_DS:
case DNS_TYPE_DNSKEY:
case DNS_TYPE_RRSIG:
case DNS_TYPE_NSEC:
case DNS_TYPE_NSEC3:
return -EINVAL;
case DNS_TYPE_SSHFP:
*out = rr->sshfp.fingerprint;
return rr->sshfp.fingerprint_size;
case DNS_TYPE_TLSA:
*out = rr->tlsa.data;
return rr->tlsa.data_size;
case DNS_TYPE_OPENPGPKEY:
default:
*out = rr->generic.data;
return rr->generic.data_size;
}
}
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, 0, &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;
}
2018-11-27 14:25:20 +01:00
void dns_resource_record_hash_func(const DnsResourceRecord *rr, struct siphash *state) {
assert(rr);
dns_resource_key_hash_func(rr->key, state);
switch (rr->unparsable ? _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;
2015-02-02 01:17:24 +01:00
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);
2015-02-02 01:17:24 +01:00
break;
2016-01-31 22:21:00 +01:00
case DNS_TYPE_CAA:
siphash24_compress(&rr->caa.flags, sizeof(rr->caa.flags), state);
string_hash_func(rr->caa.tag, state);
siphash24_compress(rr->caa.value, rr->caa.value_size, state);
2015-02-02 01:17:24 +01:00
break;
2015-02-02 02:54:15 +01:00
case DNS_TYPE_OPENPGPKEY:
default:
siphash24_compress(rr->generic.data, rr->generic.data_size, state);
break;
}
}
2018-11-27 14:25:20 +01:00
static int dns_resource_record_compare_func(const DnsResourceRecord *x, const DnsResourceRecord *y) {
int r;
2018-11-27 14:25:20 +01:00
r = dns_resource_key_compare_func(x->key, y->key);
if (r != 0)
return r;
if (dns_resource_record_equal(x, y))
return 0;
/* We still use CMP() here, even though don't implement proper
* ordering, since the hashtable doesn't need ordering anyway. */
return CMP(x, y);
}
2018-11-27 14:25:20 +01:00
DEFINE_HASH_OPS(dns_resource_record_hash_ops, DnsResourceRecord, dns_resource_record_hash_func, dns_resource_record_compare_func);
DnsResourceRecord *dns_resource_record_copy(DnsResourceRecord *rr) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *copy = NULL;
DnsResourceRecord *t;
assert(rr);
copy = dns_resource_record_new(rr->key);
if (!copy)
return NULL;
copy->ttl = rr->ttl;
copy->expiry = rr->expiry;
copy->n_skip_labels_signer = rr->n_skip_labels_signer;
copy->n_skip_labels_source = rr->n_skip_labels_source;
copy->unparsable = rr->unparsable;
switch (rr->unparsable ? _DNS_TYPE_INVALID : rr->key->type) {
case DNS_TYPE_SRV:
copy->srv.priority = rr->srv.priority;
copy->srv.weight = rr->srv.weight;
copy->srv.port = rr->srv.port;
copy->srv.name = strdup(rr->srv.name);
if (!copy->srv.name)
return NULL;
break;
case DNS_TYPE_PTR:
case DNS_TYPE_NS:
case DNS_TYPE_CNAME:
case DNS_TYPE_DNAME:
copy->ptr.name = strdup(rr->ptr.name);
if (!copy->ptr.name)
return NULL;
break;
case DNS_TYPE_HINFO:
copy->hinfo.cpu = strdup(rr->hinfo.cpu);
if (!copy->hinfo.cpu)
return NULL;
copy->hinfo.os = strdup(rr->hinfo.os);
if (!copy->hinfo.os)
return NULL;
break;
case DNS_TYPE_TXT:
case DNS_TYPE_SPF:
copy->txt.items = dns_txt_item_copy(rr->txt.items);
if (!copy->txt.items)
return NULL;
break;
case DNS_TYPE_A:
copy->a = rr->a;
break;
case DNS_TYPE_AAAA:
copy->aaaa = rr->aaaa;
break;
case DNS_TYPE_SOA:
copy->soa.mname = strdup(rr->soa.mname);
if (!copy->soa.mname)
return NULL;
copy->soa.rname = strdup(rr->soa.rname);
if (!copy->soa.rname)
return NULL;
copy->soa.serial = rr->soa.serial;
copy->soa.refresh = rr->soa.refresh;
copy->soa.retry = rr->soa.retry;
copy->soa.expire = rr->soa.expire;
copy->soa.minimum = rr->soa.minimum;
break;
case DNS_TYPE_MX:
copy->mx.priority = rr->mx.priority;
copy->mx.exchange = strdup(rr->mx.exchange);
if (!copy->mx.exchange)
return NULL;
break;
case DNS_TYPE_LOC:
copy->loc = rr->loc;
break;
case DNS_TYPE_SSHFP:
copy->sshfp.algorithm = rr->sshfp.algorithm;
copy->sshfp.fptype = rr->sshfp.fptype;
copy->sshfp.fingerprint = memdup(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
if (!copy->sshfp.fingerprint)
return NULL;
copy->sshfp.fingerprint_size = rr->sshfp.fingerprint_size;
break;
case DNS_TYPE_DNSKEY:
copy->dnskey.flags = rr->dnskey.flags;
copy->dnskey.protocol = rr->dnskey.protocol;
copy->dnskey.algorithm = rr->dnskey.algorithm;
copy->dnskey.key = memdup(rr->dnskey.key, rr->dnskey.key_size);
if (!copy->dnskey.key)
return NULL;
copy->dnskey.key_size = rr->dnskey.key_size;
break;
case DNS_TYPE_RRSIG:
copy->rrsig.type_covered = rr->rrsig.type_covered;
copy->rrsig.algorithm = rr->rrsig.algorithm;
copy->rrsig.labels = rr->rrsig.labels;
copy->rrsig.original_ttl = rr->rrsig.original_ttl;
copy->rrsig.expiration = rr->rrsig.expiration;
copy->rrsig.inception = rr->rrsig.inception;
copy->rrsig.key_tag = rr->rrsig.key_tag;
copy->rrsig.signer = strdup(rr->rrsig.signer);
if (!copy->rrsig.signer)
return NULL;
copy->rrsig.signature = memdup(rr->rrsig.signature, rr->rrsig.signature_size);
if (!copy->rrsig.signature)
return NULL;
copy->rrsig.signature_size = rr->rrsig.signature_size;
break;
case DNS_TYPE_NSEC:
copy->nsec.next_domain_name = strdup(rr->nsec.next_domain_name);
if (!copy->nsec.next_domain_name)
return NULL;
copy->nsec.types = bitmap_copy(rr->nsec.types);
if (!copy->nsec.types)
return NULL;
break;
case DNS_TYPE_DS:
copy->ds.key_tag = rr->ds.key_tag;
copy->ds.algorithm = rr->ds.algorithm;
copy->ds.digest_type = rr->ds.digest_type;
copy->ds.digest = memdup(rr->ds.digest, rr->ds.digest_size);
if (!copy->ds.digest)
return NULL;
copy->ds.digest_size = rr->ds.digest_size;
break;
case DNS_TYPE_NSEC3:
copy->nsec3.algorithm = rr->nsec3.algorithm;
copy->nsec3.flags = rr->nsec3.flags;
copy->nsec3.iterations = rr->nsec3.iterations;
copy->nsec3.salt = memdup(rr->nsec3.salt, rr->nsec3.salt_size);
if (!copy->nsec3.salt)
return NULL;
copy->nsec3.salt_size = rr->nsec3.salt_size;
copy->nsec3.next_hashed_name = memdup(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size);
if (!copy->nsec3.next_hashed_name)
return NULL;
copy->nsec3.next_hashed_name_size = rr->nsec3.next_hashed_name_size;
copy->nsec3.types = bitmap_copy(rr->nsec3.types);
if (!copy->nsec3.types)
return NULL;
break;
case DNS_TYPE_TLSA:
copy->tlsa.cert_usage = rr->tlsa.cert_usage;
copy->tlsa.selector = rr->tlsa.selector;
copy->tlsa.matching_type = rr->tlsa.matching_type;
copy->tlsa.data = memdup(rr->tlsa.data, rr->tlsa.data_size);
if (!copy->tlsa.data)
return NULL;
copy->tlsa.data_size = rr->tlsa.data_size;
break;
case DNS_TYPE_CAA:
copy->caa.flags = rr->caa.flags;
copy->caa.tag = strdup(rr->caa.tag);
if (!copy->caa.tag)
return NULL;
copy->caa.value = memdup(rr->caa.value, rr->caa.value_size);
if (!copy->caa.value)
return NULL;
copy->caa.value_size = rr->caa.value_size;
break;
case DNS_TYPE_OPT:
default:
copy->generic.data = memdup(rr->generic.data, rr->generic.data_size);
if (!copy->generic.data)
return NULL;
copy->generic.data_size = rr->generic.data_size;
break;
}
t = TAKE_PTR(copy);
return t;
}
int dns_resource_record_clamp_ttl(DnsResourceRecord **rr, uint32_t max_ttl) {
DnsResourceRecord *old_rr, *new_rr;
uint32_t new_ttl;
assert(rr);
old_rr = *rr;
if (old_rr->key->type == DNS_TYPE_OPT)
return -EINVAL;
new_ttl = MIN(old_rr->ttl, max_ttl);
if (new_ttl == old_rr->ttl)
return 0;
if (old_rr->n_ref == 1) {
/* Patch in place */
old_rr->ttl = new_ttl;
return 1;
}
new_rr = dns_resource_record_copy(old_rr);
if (!new_rr)
return -ENOMEM;
new_rr->ttl = new_ttl;
dns_resource_record_unref(*rr);
*rr = new_rr;
return 1;
}
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);
}
DnsTxtItem *dns_txt_item_copy(DnsTxtItem *first) {
DnsTxtItem *i, *copy = NULL, *end = NULL;
LIST_FOREACH(items, i, first) {
DnsTxtItem *j;
j = memdup(i, offsetof(DnsTxtItem, data) + i->length + 1);
if (!j) {
dns_txt_item_free_all(copy);
return NULL;
}
LIST_INSERT_AFTER(items, copy, end, j);
end = j;
}
return copy;
}
int dns_txt_item_new_empty(DnsTxtItem **ret) {
DnsTxtItem *i;
/* RFC 6763, section 6.1 suggests to treat
* empty TXT RRs as equivalent to a TXT record
* with a single empty string. */
i = malloc0(offsetof(DnsTxtItem, data) + 1); /* for safety reasons we add an extra NUL byte */
if (!i)
return -ENOMEM;
*ret = i;
return 0;
}
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_ED25519] = "ED25519",
[DNSSEC_ALGORITHM_ED448] = "ED448",
[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);