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"
29 DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
36 k = malloc0(sizeof(DnsResourceKey) + l + 1);
44 strcpy((char*) k + sizeof(DnsResourceKey), name);
49 DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
54 k = new0(DnsResourceKey, 1);
66 DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
77 DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
92 int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
95 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
99 if (a->class != b->class)
102 if (a->type != b->type)
108 int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr) {
112 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
115 if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
118 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
121 int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr) {
125 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
128 if (rr->key->type != DNS_TYPE_CNAME)
131 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
134 unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]) {
135 const DnsResourceKey *k = i;
138 ul = dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), hash_key);
139 ul = ul * hash_key[0] + ul + k->class;
140 ul = ul * hash_key[1] + ul + k->type;
145 int dns_resource_key_compare_func(const void *a, const void *b) {
146 const DnsResourceKey *x = a, *y = b;
149 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
153 if (x->type < y->type)
155 if (x->type > y->type)
158 if (x->class < y->class)
160 if (x->class > y->class)
166 int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
167 char cbuf[DECIMAL_STR_MAX(uint16_t)], tbuf[DECIMAL_STR_MAX(uint16_t)];
171 c = dns_class_to_string(key->class);
173 sprintf(cbuf, "%i", key->class);
177 t = dns_type_to_string(key->type);
179 sprintf(tbuf, "%i", key->type);
183 if (asprintf(&s, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key), c, t) < 0)
190 DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
191 DnsResourceRecord *rr;
193 rr = new0(DnsResourceRecord, 1);
198 rr->key = dns_resource_key_ref(key);
203 DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
204 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
206 key = dns_resource_key_new(class, type, name);
210 return dns_resource_record_new(key);
213 DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
217 assert(rr->n_ref > 0);
223 DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
227 assert(rr->n_ref > 0);
235 switch(rr->key->type) {
255 strv_free(rr->txt.strings);
264 free(rr->mx.exchange);
277 free(rr->generic.data);
280 dns_resource_key_unref(rr->key);
288 int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
289 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
290 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
291 _cleanup_free_ char *ptr = NULL;
298 r = dns_name_reverse(family, address, &ptr);
302 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
308 rr = dns_resource_record_new(key);
312 rr->ptr.name = strdup(hostname);
322 int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
328 r = dns_resource_key_equal(a->key, b->key);
332 if (a->unparseable != b->unparseable)
335 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
338 r = dns_name_equal(a->srv.name, b->srv.name);
342 return a->srv.priority == b->srv.priority &&
343 a->srv.weight == b->srv.weight &&
344 a->srv.port == b->srv.port;
350 return dns_name_equal(a->ptr.name, b->ptr.name);
353 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
354 strcaseeq(a->hinfo.os, b->hinfo.os);
356 case DNS_TYPE_SPF: /* exactly the same as TXT */
360 for (i = 0; a->txt.strings[i] || b->txt.strings[i]; i++)
361 if (!streq_ptr(a->txt.strings[i], b->txt.strings[i]))
367 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
370 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
373 r = dns_name_equal(a->soa.mname, b->soa.mname);
376 r = dns_name_equal(a->soa.rname, b->soa.rname);
380 return a->soa.serial == b->soa.serial &&
381 a->soa.refresh == b->soa.refresh &&
382 a->soa.retry == b->soa.retry &&
383 a->soa.expire == b->soa.expire &&
384 a->soa.minimum == b->soa.minimum;
387 if (a->mx.priority != b->mx.priority)
390 return dns_name_equal(a->mx.exchange, b->mx.exchange);
393 assert(a->loc.version == b->loc.version);
395 return a->loc.size == b->loc.size &&
396 a->loc.horiz_pre == b->loc.horiz_pre &&
397 a->loc.vert_pre == b->loc.vert_pre &&
398 a->loc.latitude == b->loc.latitude &&
399 a->loc.longitude == b->loc.longitude &&
400 a->loc.altitude == b->loc.altitude;
403 return a->sshfp.algorithm == b->sshfp.algorithm &&
404 a->sshfp.fptype == b->sshfp.fptype &&
405 a->sshfp.key_size == b->sshfp.key_size &&
406 memcmp(a->sshfp.key, b->sshfp.key, a->sshfp.key_size) == 0;
409 return a->generic.size == b->generic.size &&
410 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
414 static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
415 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
417 char NS = latitude >= 1U<<31 ? 'N' : 'S';
418 char EW = longitude >= 1U<<31 ? 'E' : 'W';
420 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
421 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
422 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
423 double siz = (size >> 4) * exp10((double) (size & 0xF));
424 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
425 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
427 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
430 (lat % 60000) / 1000.,
434 (lon % 60000) / 1000.,
445 int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
446 _cleanup_free_ char *k = NULL;
452 r = dns_resource_key_to_string(rr->key, &k);
456 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
459 r = asprintf(&s, "%s %u %u %u %s",
464 strna(rr->srv.name));
473 s = strjoin(k, " ", rr->ptr.name, NULL);
480 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
485 case DNS_TYPE_SPF: /* exactly the same as TXT */
487 _cleanup_free_ char *t;
489 t = strv_join_quoted(rr->txt.strings);
493 s = strjoin(k, " ", t, NULL);
501 _cleanup_free_ char *x = NULL;
503 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
507 s = strjoin(k, " ", x, NULL);
513 case DNS_TYPE_AAAA: {
514 _cleanup_free_ char *x = NULL;
516 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &x);
520 s = strjoin(k, " ", x, NULL);
527 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
529 strna(rr->soa.mname),
530 strna(rr->soa.rname),
541 r = asprintf(&s, "%s %u %s",
550 _cleanup_free_ char *loc;
551 assert(rr->loc.version == 0);
553 loc = format_location(rr->loc.latitude,
562 s = strjoin(k, " ", loc, NULL);
569 case DNS_TYPE_SSHFP: {
570 _cleanup_free_ char *x = NULL;
572 x = hexmem(rr->sshfp.key, rr->sshfp.key_size);
576 r = asprintf(&s, "%s %u %u %s",
587 _cleanup_free_ char *x = NULL;
589 x = hexmem(rr->generic.data, rr->generic.size);
593 s = strjoin(k, " ", x, NULL);
603 const char *dns_class_to_string(uint16_t class) {
617 int dns_class_from_string(const char *s, uint16_t *class) {
621 if (strcaseeq(s, "IN"))
622 *class = DNS_CLASS_IN;
623 else if (strcaseeq(s, "ANY"))
624 *class = DNS_TYPE_ANY;
631 static const struct {
636 { DNS_TYPE_NS, "NS" },
637 { DNS_TYPE_CNAME, "CNAME" },
638 { DNS_TYPE_SOA, "SOA" },
639 { DNS_TYPE_PTR, "PTR" },
640 { DNS_TYPE_HINFO, "HINFO" },
641 { DNS_TYPE_MX, "MX" },
642 { DNS_TYPE_TXT, "TXT" },
643 { DNS_TYPE_AAAA, "AAAA" },
644 { DNS_TYPE_LOC, "LOC" },
645 { DNS_TYPE_SRV, "SRV" },
646 { DNS_TYPE_SSHFP, "SSHFP" },
647 { DNS_TYPE_SPF, "SPF" },
648 { DNS_TYPE_DNAME, "DNAME" },
649 { DNS_TYPE_ANY, "ANY" },
650 { DNS_TYPE_OPT, "OPT" },
651 { DNS_TYPE_TKEY, "TKEY" },
652 { DNS_TYPE_TSIG, "TSIG" },
653 { DNS_TYPE_IXFR, "IXFR" },
654 { DNS_TYPE_AXFR, "AXFR" },
657 const char *dns_type_to_string(uint16_t type) {
660 for (i = 0; i < ELEMENTSOF(dns_types); i++)
661 if (dns_types[i].type == type)
662 return dns_types[i].name;
667 int dns_type_from_string(const char *s, uint16_t *type) {
673 for (i = 0; i < ELEMENTSOF(dns_types); i++)
674 if (strcaseeq(dns_types[i].name, s)) {
675 *type = dns_types[i].type;