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/>.
22 #include "resolved-dns-domain.h"
23 #include "resolved-dns-rr.h"
25 DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
32 k = malloc0(sizeof(DnsResourceKey) + l + 1);
40 strcpy((char*) k + sizeof(DnsResourceKey), name);
45 DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
50 k = new0(DnsResourceKey, 1);
62 DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
73 DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
88 int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
91 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
95 if (a->class != b->class)
98 if (a->type != b->type)
104 int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr) {
108 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
111 if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
114 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
117 int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr) {
121 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
124 if (rr->key->type != DNS_TYPE_CNAME)
127 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
130 unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]) {
131 const DnsResourceKey *k = i;
134 ul = dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), hash_key);
135 ul = ul * hash_key[0] + ul + k->class;
136 ul = ul * hash_key[1] + ul + k->type;
141 int dns_resource_key_compare_func(const void *a, const void *b) {
142 const DnsResourceKey *x = a, *y = b;
145 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
149 if (x->type < y->type)
151 if (x->type > y->type)
154 if (x->class < y->class)
156 if (x->class > y->class)
162 int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
163 char cbuf[DECIMAL_STR_MAX(uint16_t)], tbuf[DECIMAL_STR_MAX(uint16_t)];
167 c = dns_class_to_string(key->class);
169 sprintf(cbuf, "%i", key->class);
173 t = dns_type_to_string(key->type);
175 sprintf(tbuf, "%i", key->type);
179 s = strjoin(DNS_RESOURCE_KEY_NAME(key), " ", c, " ", t, NULL);
187 DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
188 DnsResourceRecord *rr;
190 rr = new0(DnsResourceRecord, 1);
195 rr->key = dns_resource_key_ref(key);
200 DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
201 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
203 key = dns_resource_key_new(class, type, name);
207 return dns_resource_record_new(key);
210 DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
214 assert(rr->n_ref > 0);
220 DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
224 assert(rr->n_ref > 0);
232 if (IN_SET(rr->key->type, DNS_TYPE_PTR, DNS_TYPE_NS, DNS_TYPE_CNAME))
234 else if (rr->key->type == DNS_TYPE_HINFO) {
237 } else if (rr->key->type == DNS_TYPE_SOA) {
240 } else if (rr->key->type == DNS_TYPE_MX) {
241 free(rr->mx.exchange);
242 } else if (!IN_SET(rr->key->type, DNS_TYPE_A, DNS_TYPE_AAAA))
243 free(rr->generic.data);
245 dns_resource_key_unref(rr->key);
253 int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
254 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
255 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
256 _cleanup_free_ char *ptr = NULL;
263 r = dns_name_reverse(family, address, &ptr);
267 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
273 rr = dns_resource_record_new(key);
277 rr->ptr.name = strdup(hostname);
287 int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
293 r = dns_resource_key_equal(a->key, b->key);
297 switch (a->key->type) {
302 return dns_name_equal(a->ptr.name, b->ptr.name);
305 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
306 strcaseeq(a->hinfo.os, b->hinfo.os);
309 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
312 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
315 r = dns_name_equal(a->soa.mname, b->soa.mname);
318 r = dns_name_equal(a->soa.rname, b->soa.rname);
322 return a->soa.serial == b->soa.serial &&
323 a->soa.refresh == b->soa.refresh &&
324 a->soa.retry == b->soa.retry &&
325 a->soa.expire == b->soa.expire &&
326 a->soa.minimum == b->soa.minimum;
328 if (a->mx.priority != b->mx.priority)
331 return dns_name_equal(a->mx.exchange, b->mx.exchange);
334 return a->generic.size == b->generic.size &&
335 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
339 int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
340 _cleanup_free_ char *k = NULL;
346 r = dns_resource_key_to_string(rr->key, &k);
350 switch (rr->key->type) {
355 s = strjoin(k, " ", rr->ptr.name, NULL);
362 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
368 _cleanup_free_ char *x = NULL;
370 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
374 s = strjoin(k, " ", x, NULL);
380 case DNS_TYPE_AAAA: {
381 _cleanup_free_ char *x = NULL;
383 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &x);
387 s = strjoin(k, " ", x, NULL);
394 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
396 strna(rr->soa.mname),
397 strna(rr->soa.rname),
408 r = asprintf(&s, "%s %u %s",
417 _cleanup_free_ char *x = NULL;
419 x = hexmem(rr->generic.data, rr->generic.size);
423 s = strjoin(k, " ", x, NULL);
433 const char *dns_class_to_string(uint16_t class) {
447 int dns_class_from_string(const char *s, uint16_t *class) {
451 if (strcaseeq(s, "IN"))
452 *class = DNS_CLASS_IN;
453 else if (strcaseeq(s, "ANY"))
454 *class = DNS_TYPE_ANY;
461 static const struct {
466 { DNS_TYPE_NS, "NS" },
467 { DNS_TYPE_CNAME, "CNAME" },
468 { DNS_TYPE_SOA, "SOA" },
469 { DNS_TYPE_PTR, "PTR" },
470 { DNS_TYPE_HINFO, "HINFO" },
471 { DNS_TYPE_MX, "MX" },
472 { DNS_TYPE_TXT, "TXT" },
473 { DNS_TYPE_AAAA, "AAAA" },
474 { DNS_TYPE_SRV, "SRV" },
475 { DNS_TYPE_SSHFP, "SSHFP" },
476 { DNS_TYPE_DNAME, "DNAME" },
477 { DNS_TYPE_ANY, "ANY" },
478 { DNS_TYPE_OPT, "OPT" },
479 { DNS_TYPE_TKEY, "TKEY" },
480 { DNS_TYPE_TSIG, "TSIG" },
481 { DNS_TYPE_IXFR, "IXFR" },
482 { DNS_TYPE_AXFR, "AXFR" },
486 const char *dns_type_to_string(uint16_t type) {
489 for (i = 0; i < ELEMENTSOF(dns_types); i++)
490 if (dns_types[i].type == type)
491 return dns_types[i].name;
496 int dns_type_from_string(const char *s, uint16_t *type) {
502 for (i = 0; i < ELEMENTSOF(dns_types); i++)
503 if (strcaseeq(dns_types[i].name, s)) {
504 *type = dns_types[i].type;