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);
283 free(rr->generic.data);
286 dns_resource_key_unref(rr->key);
294 int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
295 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
296 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
297 _cleanup_free_ char *ptr = NULL;
304 r = dns_name_reverse(family, address, &ptr);
308 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
314 rr = dns_resource_record_new(key);
318 rr->ptr.name = strdup(hostname);
328 int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
334 r = dns_resource_key_equal(a->key, b->key);
338 if (a->unparseable != b->unparseable)
341 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
344 r = dns_name_equal(a->srv.name, b->srv.name);
348 return a->srv.priority == b->srv.priority &&
349 a->srv.weight == b->srv.weight &&
350 a->srv.port == b->srv.port;
356 return dns_name_equal(a->ptr.name, b->ptr.name);
359 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
360 strcaseeq(a->hinfo.os, b->hinfo.os);
362 case DNS_TYPE_SPF: /* exactly the same as TXT */
366 for (i = 0; a->txt.strings[i] || b->txt.strings[i]; i++)
367 if (!streq_ptr(a->txt.strings[i], b->txt.strings[i]))
373 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
376 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
379 r = dns_name_equal(a->soa.mname, b->soa.mname);
382 r = dns_name_equal(a->soa.rname, b->soa.rname);
386 return a->soa.serial == b->soa.serial &&
387 a->soa.refresh == b->soa.refresh &&
388 a->soa.retry == b->soa.retry &&
389 a->soa.expire == b->soa.expire &&
390 a->soa.minimum == b->soa.minimum;
393 if (a->mx.priority != b->mx.priority)
396 return dns_name_equal(a->mx.exchange, b->mx.exchange);
399 assert(a->loc.version == b->loc.version);
401 return a->loc.size == b->loc.size &&
402 a->loc.horiz_pre == b->loc.horiz_pre &&
403 a->loc.vert_pre == b->loc.vert_pre &&
404 a->loc.latitude == b->loc.latitude &&
405 a->loc.longitude == b->loc.longitude &&
406 a->loc.altitude == b->loc.altitude;
409 return a->sshfp.algorithm == b->sshfp.algorithm &&
410 a->sshfp.fptype == b->sshfp.fptype &&
411 a->sshfp.key_size == b->sshfp.key_size &&
412 memcmp(a->sshfp.key, b->sshfp.key, a->sshfp.key_size) == 0;
414 case DNS_TYPE_DNSKEY:
415 return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag &&
416 a->dnskey.sep_flag == b->dnskey.sep_flag &&
417 a->dnskey.algorithm == b->dnskey.algorithm &&
418 a->dnskey.key_size == b->dnskey.key_size &&
419 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
422 return a->generic.size == b->generic.size &&
423 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
427 static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
428 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
430 char NS = latitude >= 1U<<31 ? 'N' : 'S';
431 char EW = longitude >= 1U<<31 ? 'E' : 'W';
433 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
434 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
435 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
436 double siz = (size >> 4) * exp10((double) (size & 0xF));
437 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
438 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
440 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
443 (lat % 60000) / 1000.,
447 (lon % 60000) / 1000.,
458 int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
459 _cleanup_free_ char *k = NULL, *t = NULL;
465 r = dns_resource_key_to_string(rr->key, &k);
469 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
472 r = asprintf(&s, "%s %u %u %u %s",
477 strna(rr->srv.name));
486 s = strjoin(k, " ", rr->ptr.name, NULL);
493 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
498 case DNS_TYPE_SPF: /* exactly the same as TXT */
500 t = strv_join_quoted(rr->txt.strings);
504 s = strjoin(k, " ", t, NULL);
511 _cleanup_free_ char *x = NULL;
513 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
517 s = strjoin(k, " ", x, NULL);
524 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
528 s = strjoin(k, " ", t, NULL);
534 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
536 strna(rr->soa.mname),
537 strna(rr->soa.rname),
548 r = asprintf(&s, "%s %u %s",
557 assert(rr->loc.version == 0);
559 t = format_location(rr->loc.latitude,
568 s = strjoin(k, " ", t, NULL);
574 t = hexmem(rr->sshfp.key, rr->sshfp.key_size);
578 r = asprintf(&s, "%s %u %u %s",
587 case DNS_TYPE_DNSKEY:
588 t = hexmem(rr->dnskey.key, rr->dnskey.key_size);
592 r = asprintf(&s, "%s %u 3 %u %s",
595 rr->dnskey.algorithm,
602 t = hexmem(rr->generic.data, rr->generic.size);
606 s = strjoin(k, " ", t, NULL);
616 const char *dns_class_to_string(uint16_t class) {
630 int dns_class_from_string(const char *s, uint16_t *class) {
634 if (strcaseeq(s, "IN"))
635 *class = DNS_CLASS_IN;
636 else if (strcaseeq(s, "ANY"))
637 *class = DNS_TYPE_ANY;