1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "resolved-dns-domain.h"
27 #include "resolved-dns-rr.h"
28 #include "resolved-dns-packet.h"
31 DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
38 k = malloc0(sizeof(DnsResourceKey) + l + 1);
46 strcpy((char*) k + sizeof(DnsResourceKey), name);
51 DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
56 k = new0(DnsResourceKey, 1);
68 DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
79 DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
94 int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
97 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
101 if (a->class != b->class)
104 if (a->type != b->type)
110 int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr) {
114 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
117 if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
120 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
123 int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr) {
127 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
130 if (rr->key->type != DNS_TYPE_CNAME)
133 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
136 unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]) {
137 const DnsResourceKey *k = i;
140 ul = dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), hash_key);
141 ul = ul * hash_key[0] + ul + k->class;
142 ul = ul * hash_key[1] + ul + k->type;
147 int dns_resource_key_compare_func(const void *a, const void *b) {
148 const DnsResourceKey *x = a, *y = b;
151 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
155 if (x->type < y->type)
157 if (x->type > y->type)
160 if (x->class < y->class)
162 if (x->class > y->class)
168 int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
169 char cbuf[DECIMAL_STR_MAX(uint16_t)], tbuf[DECIMAL_STR_MAX(uint16_t)];
173 c = dns_class_to_string(key->class);
175 sprintf(cbuf, "%i", key->class);
179 t = dns_type_to_string(key->type);
181 sprintf(tbuf, "%i", key->type);
185 if (asprintf(&s, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key), c, t) < 0)
192 DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
193 DnsResourceRecord *rr;
195 rr = new0(DnsResourceRecord, 1);
200 rr->key = dns_resource_key_ref(key);
205 DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
206 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
208 key = dns_resource_key_new(class, type, name);
212 return dns_resource_record_new(key);
215 DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
219 assert(rr->n_ref > 0);
225 DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
229 assert(rr->n_ref > 0);
237 switch(rr->key->type) {
257 strv_free(rr->txt.strings);
266 free(rr->mx.exchange);
273 case DNS_TYPE_DNSKEY:
274 free(rr->dnskey.key);
278 free(rr->rrsig.signer);
279 free(rr->rrsig.signature);
288 free(rr->generic.data);
291 dns_resource_key_unref(rr->key);
299 int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
300 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
301 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
302 _cleanup_free_ char *ptr = NULL;
309 r = dns_name_reverse(family, address, &ptr);
313 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
319 rr = dns_resource_record_new(key);
323 rr->ptr.name = strdup(hostname);
333 int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
339 r = dns_resource_key_equal(a->key, b->key);
343 if (a->unparseable != b->unparseable)
346 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
349 r = dns_name_equal(a->srv.name, b->srv.name);
353 return a->srv.priority == b->srv.priority &&
354 a->srv.weight == b->srv.weight &&
355 a->srv.port == b->srv.port;
361 return dns_name_equal(a->ptr.name, b->ptr.name);
364 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
365 strcaseeq(a->hinfo.os, b->hinfo.os);
367 case DNS_TYPE_SPF: /* exactly the same as TXT */
371 for (i = 0; a->txt.strings[i] || b->txt.strings[i]; i++)
372 if (!streq_ptr(a->txt.strings[i], b->txt.strings[i]))
378 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
381 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
384 r = dns_name_equal(a->soa.mname, b->soa.mname);
387 r = dns_name_equal(a->soa.rname, b->soa.rname);
391 return a->soa.serial == b->soa.serial &&
392 a->soa.refresh == b->soa.refresh &&
393 a->soa.retry == b->soa.retry &&
394 a->soa.expire == b->soa.expire &&
395 a->soa.minimum == b->soa.minimum;
398 if (a->mx.priority != b->mx.priority)
401 return dns_name_equal(a->mx.exchange, b->mx.exchange);
404 assert(a->loc.version == b->loc.version);
406 return a->loc.size == b->loc.size &&
407 a->loc.horiz_pre == b->loc.horiz_pre &&
408 a->loc.vert_pre == b->loc.vert_pre &&
409 a->loc.latitude == b->loc.latitude &&
410 a->loc.longitude == b->loc.longitude &&
411 a->loc.altitude == b->loc.altitude;
414 return a->sshfp.algorithm == b->sshfp.algorithm &&
415 a->sshfp.fptype == b->sshfp.fptype &&
416 a->sshfp.key_size == b->sshfp.key_size &&
417 memcmp(a->sshfp.key, b->sshfp.key, a->sshfp.key_size) == 0;
419 case DNS_TYPE_DNSKEY:
420 return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag &&
421 a->dnskey.sep_flag == b->dnskey.sep_flag &&
422 a->dnskey.algorithm == b->dnskey.algorithm &&
423 a->dnskey.key_size == b->dnskey.key_size &&
424 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
427 /* do the fast comparisons first */
428 if (a->rrsig.type_covered != a->rrsig.type_covered ||
429 a->rrsig.algorithm != a->rrsig.algorithm ||
430 a->rrsig.labels != a->rrsig.labels ||
431 a->rrsig.original_ttl != a->rrsig.original_ttl ||
432 a->rrsig.expiration != a->rrsig.expiration ||
433 a->rrsig.inception != a->rrsig.inception ||
434 a->rrsig.key_tag != a->rrsig.key_tag ||
435 a->rrsig.signature_size != b->rrsig.signature_size ||
436 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
439 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
442 return a->generic.size == b->generic.size &&
443 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
447 static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
448 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
450 char NS = latitude >= 1U<<31 ? 'N' : 'S';
451 char EW = longitude >= 1U<<31 ? 'E' : 'W';
453 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
454 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
455 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
456 double siz = (size >> 4) * exp10((double) (size & 0xF));
457 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
458 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
460 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
463 (lat % 60000) / 1000.,
467 (lon % 60000) / 1000.,
478 int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
479 _cleanup_free_ char *k = NULL, *t = NULL;
485 r = dns_resource_key_to_string(rr->key, &k);
489 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
492 r = asprintf(&s, "%s %u %u %u %s",
497 strna(rr->srv.name));
506 s = strjoin(k, " ", rr->ptr.name, NULL);
513 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
518 case DNS_TYPE_SPF: /* exactly the same as TXT */
520 t = strv_join_quoted(rr->txt.strings);
524 s = strjoin(k, " ", t, NULL);
531 _cleanup_free_ char *x = NULL;
533 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
537 s = strjoin(k, " ", x, NULL);
544 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
548 s = strjoin(k, " ", t, NULL);
554 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
556 strna(rr->soa.mname),
557 strna(rr->soa.rname),
568 r = asprintf(&s, "%s %u %s",
577 assert(rr->loc.version == 0);
579 t = format_location(rr->loc.latitude,
588 s = strjoin(k, " ", t, NULL);
594 t = hexmem(rr->sshfp.key, rr->sshfp.key_size);
598 r = asprintf(&s, "%s %u %u %s",
607 case DNS_TYPE_DNSKEY: {
610 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
612 t = hexmem(rr->dnskey.key, rr->dnskey.key_size);
616 r = asprintf(&s, "%s %u 3 %.*s%.*u %s",
620 alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
627 case DNS_TYPE_RRSIG: {
628 const char *type, *alg;
630 type = dns_type_to_string(rr->rrsig.type_covered);
631 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
633 t = hexmem(rr->rrsig.signature, rr->rrsig.signature_size);
638 * http://tools.ietf.org/html/rfc3597#section-5 */
640 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %u %u %u %s %s",
643 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
645 alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
647 rr->rrsig.original_ttl,
648 rr->rrsig.expiration,
659 t = hexmem(rr->generic.data, rr->generic.size);
663 s = strjoin(k, " ", t, NULL);
673 const char *dns_class_to_string(uint16_t class) {
687 int dns_class_from_string(const char *s, uint16_t *class) {
691 if (strcaseeq(s, "IN"))
692 *class = DNS_CLASS_IN;
693 else if (strcaseeq(s, "ANY"))
694 *class = DNS_TYPE_ANY;