]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-rr.c
resolve-host: add option to list protocols
[thirdparty/systemd.git] / src / resolve / resolved-dns-rr.c
CommitLineData
74b2466e
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
0dae31d4
ZJS
22#include <math.h>
23
b5efdb8a 24#include "alloc-util.h"
4ad7f276 25#include "dns-domain.h"
7263f724 26#include "dns-type.h"
e4e73a63 27#include "hexdecoct.h"
fc8eec10 28#include "resolved-dns-dnssec.h"
07630cea 29#include "resolved-dns-packet.h"
e4e73a63 30#include "resolved-dns-rr.h"
8730bccf 31#include "string-table.h"
07630cea
LP
32#include "string-util.h"
33#include "strv.h"
d7671a3e 34#include "terminal-util.h"
74b2466e 35
faa133f3
LP
36DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
37 DnsResourceKey *k;
38 size_t l;
74b2466e 39
faa133f3
LP
40 assert(name);
41
42 l = strlen(name);
43 k = malloc0(sizeof(DnsResourceKey) + l + 1);
44 if (!k)
45 return NULL;
46
47 k->n_ref = 1;
48 k->class = class;
49 k->type = type;
50
51 strcpy((char*) k + sizeof(DnsResourceKey), name);
52
53 return k;
54}
55
36d9205d 56DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) {
58db254a
LP
57 int r;
58
36d9205d
TG
59 assert(key);
60 assert(cname);
61
58db254a
LP
62 assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME));
63
64 if (cname->key->type == DNS_TYPE_CNAME)
65 return dns_resource_key_new(key->class, key->type, cname->cname.name);
66 else {
67 DnsResourceKey *k;
68 char *destination = NULL;
69
70 r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination);
71 if (r < 0)
72 return NULL;
73 if (r == 0)
74 return dns_resource_key_ref((DnsResourceKey*) key);
75
76 k = dns_resource_key_new_consume(key->class, key->type, destination);
77 if (!k) {
78 free(destination);
79 return NULL;
80 }
81
82 return k;
83 }
36d9205d
TG
84}
85
801ad6a6
LP
86int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name) {
87 DnsResourceKey *new_key;
88 char *joined;
89 int r;
90
91 assert(ret);
92 assert(key);
93 assert(name);
94
dc477e73 95 if (dns_name_is_root(name)) {
801ad6a6
LP
96 *ret = dns_resource_key_ref(key);
97 return 0;
98 }
99
100 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), name, &joined);
101 if (r < 0)
102 return r;
103
104 new_key = dns_resource_key_new_consume(key->class, key->type, joined);
105 if (!new_key) {
106 free(joined);
107 return -ENOMEM;
108 }
109
110 *ret = new_key;
111 return 0;
112}
113
faa133f3
LP
114DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
115 DnsResourceKey *k;
116
117 assert(name);
118
119 k = new0(DnsResourceKey, 1);
120 if (!k)
121 return NULL;
122
123 k->n_ref = 1;
124 k->class = class;
125 k->type = type;
126 k->_name = name;
127
128 return k;
129}
130
131DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
132
133 if (!k)
134 return NULL;
135
1b4f6e79
LP
136 /* Static/const keys created with DNS_RESOURCE_KEY_CONST will
137 * set this to -1, they should not be reffed/unreffed */
138 assert(k->n_ref != (unsigned) -1);
139
faa133f3
LP
140 assert(k->n_ref > 0);
141 k->n_ref++;
142
143 return k;
144}
145
146DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
147 if (!k)
148 return NULL;
149
1b4f6e79 150 assert(k->n_ref != (unsigned) -1);
faa133f3
LP
151 assert(k->n_ref > 0);
152
153 if (k->n_ref == 1) {
154 free(k->_name);
155 free(k);
156 } else
157 k->n_ref--;
158
159 return NULL;
160}
161
28b9b764
LP
162bool dns_resource_key_is_address(const DnsResourceKey *key) {
163 assert(key);
164
165 /* Check if this is an A or AAAA resource key */
166
167 return key->class == DNS_CLASS_IN && IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_AAAA);
168}
169
faa133f3
LP
170int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
171 int r;
172
4d247a6c
LP
173 if (a == b)
174 return 1;
175
faa133f3
LP
176 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
177 if (r <= 0)
178 return r;
179
180 if (a->class != b->class)
181 return 0;
182
183 if (a->type != b->type)
184 return 0;
185
186 return 1;
187}
188
105e1512 189int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, const char *search_domain) {
801ad6a6
LP
190 int r;
191
faa133f3
LP
192 assert(key);
193 assert(rr);
194
4d247a6c
LP
195 if (key == rr->key)
196 return 1;
197
801ad6a6
LP
198 /* Checks if an rr matches the specified key. If a search
199 * domain is specified, it will also be checked if the key
200 * with the search domain suffixed might match the RR. */
201
faa133f3
LP
202 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
203 return 0;
204
205 if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
206 return 0;
207
801ad6a6
LP
208 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
209 if (r != 0)
210 return r;
211
212 if (search_domain) {
213 _cleanup_free_ char *joined = NULL;
214
215 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
216 if (r < 0)
217 return r;
218
219 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), joined);
220 }
221
222 return 0;
faa133f3
LP
223}
224
5d27351f 225int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain) {
801ad6a6
LP
226 int r;
227
faa133f3 228 assert(key);
5d27351f 229 assert(cname);
faa133f3 230
5d27351f 231 if (cname->class != key->class && key->class != DNS_CLASS_ANY)
faa133f3
LP
232 return 0;
233
5d27351f
TG
234 if (cname->type == DNS_TYPE_CNAME)
235 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname));
236 else if (cname->type == DNS_TYPE_DNAME)
237 r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname));
58db254a 238 else
faa133f3 239 return 0;
801ad6a6
LP
240
241 if (r != 0)
242 return r;
243
244 if (search_domain) {
245 _cleanup_free_ char *joined = NULL;
246
247 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
248 if (r < 0)
249 return r;
250
5d27351f
TG
251 if (cname->type == DNS_TYPE_CNAME)
252 return dns_name_equal(joined, DNS_RESOURCE_KEY_NAME(cname));
253 else if (cname->type == DNS_TYPE_DNAME)
254 return dns_name_endswith(joined, DNS_RESOURCE_KEY_NAME(cname));
801ad6a6
LP
255 }
256
257 return 0;
547973de
LP
258}
259
260int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *soa) {
261 assert(soa);
262 assert(key);
263
264 /* Checks whether 'soa' is a SOA record for the specified key. */
265
65b200e7 266 if (soa->class != key->class)
547973de 267 return 0;
801ad6a6 268
547973de
LP
269 if (soa->type != DNS_TYPE_SOA)
270 return 0;
271
0936416a 272 return dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(soa));
74b2466e
LP
273}
274
b826ab58 275static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
322345fd 276 const DnsResourceKey *k = i;
322345fd 277
b826ab58 278 assert(k);
322345fd 279
b826ab58
TG
280 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state);
281 siphash24_compress(&k->class, sizeof(k->class), state);
282 siphash24_compress(&k->type, sizeof(k->type), state);
322345fd
LP
283}
284
d5099efc 285static int dns_resource_key_compare_func(const void *a, const void *b) {
322345fd
LP
286 const DnsResourceKey *x = a, *y = b;
287 int ret;
288
faa133f3 289 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
322345fd
LP
290 if (ret != 0)
291 return ret;
292
293 if (x->type < y->type)
294 return -1;
295 if (x->type > y->type)
296 return 1;
297
298 if (x->class < y->class)
299 return -1;
300 if (x->class > y->class)
301 return 1;
302
303 return 0;
304}
305
d5099efc
MS
306const struct hash_ops dns_resource_key_hash_ops = {
307 .hash = dns_resource_key_hash_func,
308 .compare = dns_resource_key_compare_func
309};
310
2d4c5cbc 311int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
d23a27a9 312 char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
f2af5ea3 313 const char *c, *t, *n;
2d4c5cbc
LP
314 char *s;
315
6af47493
LP
316 /* If we cannot convert the CLASS/TYPE into a known string,
317 use the format recommended by RFC 3597, Section 5. */
318
2d4c5cbc
LP
319 c = dns_class_to_string(key->class);
320 if (!c) {
d23a27a9 321 sprintf(cbuf, "CLASS%u", key->class);
2d4c5cbc
LP
322 c = cbuf;
323 }
324
325 t = dns_type_to_string(key->type);
326 if (!t){
d23a27a9 327 sprintf(tbuf, "TYPE%u", key->type);
2d4c5cbc
LP
328 t = tbuf;
329 }
330
f2af5ea3
LP
331 n = DNS_RESOURCE_KEY_NAME(key);
332 if (asprintf(&s, "%s%s %s %-5s", n, endswith(n, ".") ? "" : ".", c, t) < 0)
2d4c5cbc
LP
333 return -ENOMEM;
334
335 *ret = s;
336 return 0;
337}
338
f57e3cd5
LP
339bool dns_resource_key_reduce(DnsResourceKey **a, DnsResourceKey **b) {
340 assert(a);
341 assert(b);
342
343 /* Try to replace one RR key by another if they are identical, thus saving a bit of memory. Note that we do
344 * this only for RR keys, not for RRs themselves, as they carry a lot of additional metadata (where they come
345 * from, validity data, and suchlike), and cannot be replaced so easily by other RRs that have the same
346 * superficial data. */
347
348 if (!*a)
349 return false;
350 if (!*b)
351 return false;
352
353 /* We refuse merging const keys */
354 if ((*a)->n_ref == (unsigned) -1)
355 return false;
356 if ((*b)->n_ref == (unsigned) -1)
357 return false;
358
359 /* Already the same? */
360 if (*a == *b)
361 return true;
362
363 /* Are they really identical? */
364 if (dns_resource_key_equal(*a, *b) <= 0)
365 return false;
366
367 /* Keep the one which already has more references. */
368 if ((*a)->n_ref > (*b)->n_ref) {
369 dns_resource_key_unref(*b);
370 *b = dns_resource_key_ref(*a);
371 } else {
372 dns_resource_key_unref(*a);
373 *a = dns_resource_key_ref(*b);
374 }
375
376 return true;
377}
378
faa133f3 379DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
74b2466e
LP
380 DnsResourceRecord *rr;
381
382 rr = new0(DnsResourceRecord, 1);
383 if (!rr)
384 return NULL;
385
386 rr->n_ref = 1;
faa133f3 387 rr->key = dns_resource_key_ref(key);
ee3d6aff 388 rr->expiry = USEC_INFINITY;
97c67192 389 rr->n_skip_labels_signer = rr->n_skip_labels_source = (unsigned) -1;
faa133f3 390
74b2466e
LP
391 return rr;
392}
393
8bf52d3d
LP
394DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
395 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
396
397 key = dns_resource_key_new(class, type, name);
398 if (!key)
399 return NULL;
400
401 return dns_resource_record_new(key);
402}
403
74b2466e
LP
404DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
405 if (!rr)
406 return NULL;
407
408 assert(rr->n_ref > 0);
409 rr->n_ref++;
410
411 return rr;
412}
413
414DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
415 if (!rr)
416 return NULL;
417
418 assert(rr->n_ref > 0);
419
420 if (rr->n_ref > 1) {
421 rr->n_ref--;
422 return NULL;
423 }
424
faa133f3 425 if (rr->key) {
9de3e329 426 switch(rr->key->type) {
9c92ce6d
LP
427
428 case DNS_TYPE_SRV:
429 free(rr->srv.name);
430 break;
431
9de3e329
ZJS
432 case DNS_TYPE_PTR:
433 case DNS_TYPE_NS:
434 case DNS_TYPE_CNAME:
8ac4e9e1 435 case DNS_TYPE_DNAME:
faa133f3 436 free(rr->ptr.name);
9de3e329 437 break;
9c92ce6d 438
9de3e329 439 case DNS_TYPE_HINFO:
faa133f3
LP
440 free(rr->hinfo.cpu);
441 free(rr->hinfo.os);
9de3e329 442 break;
9c92ce6d 443
9de3e329 444 case DNS_TYPE_TXT:
9c92ce6d 445 case DNS_TYPE_SPF:
2001c805 446 dns_txt_item_free_all(rr->txt.items);
9de3e329 447 break;
9c92ce6d 448
9de3e329 449 case DNS_TYPE_SOA:
7e8e0422
LP
450 free(rr->soa.mname);
451 free(rr->soa.rname);
9de3e329 452 break;
9c92ce6d 453
9de3e329 454 case DNS_TYPE_MX:
946c7094 455 free(rr->mx.exchange);
9de3e329 456 break;
9c92ce6d 457
abf126a3
TG
458 case DNS_TYPE_DS:
459 free(rr->ds.digest);
460 break;
461
42cc2eeb 462 case DNS_TYPE_SSHFP:
549c1a25 463 free(rr->sshfp.fingerprint);
42cc2eeb
LP
464 break;
465
8db0d2f5
ZJS
466 case DNS_TYPE_DNSKEY:
467 free(rr->dnskey.key);
468 break;
469
151226ab
ZJS
470 case DNS_TYPE_RRSIG:
471 free(rr->rrsig.signer);
472 free(rr->rrsig.signature);
473 break;
474
50f1e641
TG
475 case DNS_TYPE_NSEC:
476 free(rr->nsec.next_domain_name);
477 bitmap_free(rr->nsec.types);
478 break;
479
5d45a880
TG
480 case DNS_TYPE_NSEC3:
481 free(rr->nsec3.next_hashed_name);
482 free(rr->nsec3.salt);
483 bitmap_free(rr->nsec3.types);
484 break;
485
0dae31d4 486 case DNS_TYPE_LOC:
9de3e329
ZJS
487 case DNS_TYPE_A:
488 case DNS_TYPE_AAAA:
489 break;
9c92ce6d 490
48d45d2b
ZJS
491 case DNS_TYPE_TLSA:
492 free(rr->tlsa.data);
493 break;
494
d93a16b8 495 case DNS_TYPE_OPENPGPKEY:
9de3e329 496 default:
faa133f3 497 free(rr->generic.data);
9de3e329 498 }
322345fd 499
a8812dd7 500 free(rr->wire_format);
faa133f3
LP
501 dns_resource_key_unref(rr->key);
502 }
322345fd 503
7b50eb2e 504 free(rr->to_string);
faa133f3 505 free(rr);
322345fd 506
322345fd
LP
507 return NULL;
508}
509
623a4c97
LP
510int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
511 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
512 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
513 _cleanup_free_ char *ptr = NULL;
514 int r;
515
516 assert(ret);
517 assert(address);
518 assert(hostname);
519
520 r = dns_name_reverse(family, address, &ptr);
521 if (r < 0)
522 return r;
523
524 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
525 if (!key)
526 return -ENOMEM;
527
528 ptr = NULL;
529
530 rr = dns_resource_record_new(key);
531 if (!rr)
532 return -ENOMEM;
533
534 rr->ptr.name = strdup(hostname);
535 if (!rr->ptr.name)
536 return -ENOMEM;
537
538 *ret = rr;
539 rr = NULL;
540
541 return 0;
542}
543
78c6a153
LP
544int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
545 DnsResourceRecord *rr;
546
547 assert(ret);
548 assert(address);
549 assert(family);
550
551 if (family == AF_INET) {
552
553 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
554 if (!rr)
555 return -ENOMEM;
556
557 rr->a.in_addr = address->in;
558
559 } else if (family == AF_INET6) {
560
561 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
562 if (!rr)
563 return -ENOMEM;
564
565 rr->aaaa.in6_addr = address->in6;
566 } else
567 return -EAFNOSUPPORT;
568
569 *ret = rr;
570
571 return 0;
572}
573
322345fd
LP
574int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
575 int r;
576
577 assert(a);
578 assert(b);
579
4d247a6c
LP
580 if (a == b)
581 return 1;
582
faa133f3 583 r = dns_resource_key_equal(a->key, b->key);
322345fd
LP
584 if (r <= 0)
585 return r;
586
fd0b4602
LP
587 if (a->unparseable != b->unparseable)
588 return 0;
589
590 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
2d4c5cbc 591
9c92ce6d
LP
592 case DNS_TYPE_SRV:
593 r = dns_name_equal(a->srv.name, b->srv.name);
594 if (r <= 0)
595 return r;
596
597 return a->srv.priority == b->srv.priority &&
598 a->srv.weight == b->srv.weight &&
599 a->srv.port == b->srv.port;
600
2d4c5cbc
LP
601 case DNS_TYPE_PTR:
602 case DNS_TYPE_NS:
603 case DNS_TYPE_CNAME:
8ac4e9e1 604 case DNS_TYPE_DNAME:
322345fd 605 return dns_name_equal(a->ptr.name, b->ptr.name);
2d4c5cbc
LP
606
607 case DNS_TYPE_HINFO:
608 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
609 strcaseeq(a->hinfo.os, b->hinfo.os);
610
9de3e329 611 case DNS_TYPE_SPF: /* exactly the same as TXT */
0f84a72e 612 case DNS_TYPE_TXT:
2001c805 613 return dns_txt_item_equal(a->txt.items, b->txt.items);
2e276efc 614
2d4c5cbc 615 case DNS_TYPE_A:
322345fd 616 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
2d4c5cbc
LP
617
618 case DNS_TYPE_AAAA:
322345fd 619 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
2d4c5cbc
LP
620
621 case DNS_TYPE_SOA:
7e8e0422
LP
622 r = dns_name_equal(a->soa.mname, b->soa.mname);
623 if (r <= 0)
624 return r;
625 r = dns_name_equal(a->soa.rname, b->soa.rname);
626 if (r <= 0)
627 return r;
628
629 return a->soa.serial == b->soa.serial &&
630 a->soa.refresh == b->soa.refresh &&
631 a->soa.retry == b->soa.retry &&
632 a->soa.expire == b->soa.expire &&
633 a->soa.minimum == b->soa.minimum;
9c92ce6d 634
946c7094
ZJS
635 case DNS_TYPE_MX:
636 if (a->mx.priority != b->mx.priority)
637 return 0;
638
639 return dns_name_equal(a->mx.exchange, b->mx.exchange);
640
0dae31d4
ZJS
641 case DNS_TYPE_LOC:
642 assert(a->loc.version == b->loc.version);
643
644 return a->loc.size == b->loc.size &&
645 a->loc.horiz_pre == b->loc.horiz_pre &&
646 a->loc.vert_pre == b->loc.vert_pre &&
647 a->loc.latitude == b->loc.latitude &&
648 a->loc.longitude == b->loc.longitude &&
649 a->loc.altitude == b->loc.altitude;
650
abf126a3
TG
651 case DNS_TYPE_DS:
652 return a->ds.key_tag == b->ds.key_tag &&
653 a->ds.algorithm == b->ds.algorithm &&
654 a->ds.digest_type == b->ds.digest_type &&
655 a->ds.digest_size == b->ds.digest_size &&
656 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
657
42cc2eeb
LP
658 case DNS_TYPE_SSHFP:
659 return a->sshfp.algorithm == b->sshfp.algorithm &&
660 a->sshfp.fptype == b->sshfp.fptype &&
549c1a25
TG
661 a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
662 memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
42cc2eeb 663
8db0d2f5 664 case DNS_TYPE_DNSKEY:
f91dc240
LP
665 return a->dnskey.flags == b->dnskey.flags &&
666 a->dnskey.protocol == b->dnskey.protocol &&
8db0d2f5
ZJS
667 a->dnskey.algorithm == b->dnskey.algorithm &&
668 a->dnskey.key_size == b->dnskey.key_size &&
669 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
670
151226ab
ZJS
671 case DNS_TYPE_RRSIG:
672 /* do the fast comparisons first */
03664a62
LN
673 if (a->rrsig.type_covered != b->rrsig.type_covered ||
674 a->rrsig.algorithm != b->rrsig.algorithm ||
675 a->rrsig.labels != b->rrsig.labels ||
676 a->rrsig.original_ttl != b->rrsig.original_ttl ||
677 a->rrsig.expiration != b->rrsig.expiration ||
678 a->rrsig.inception != b->rrsig.inception ||
679 a->rrsig.key_tag != b->rrsig.key_tag ||
151226ab
ZJS
680 a->rrsig.signature_size != b->rrsig.signature_size ||
681 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
682 return false;
683
684 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
685
50f1e641
TG
686 case DNS_TYPE_NSEC:
687 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
688 bitmap_equal(a->nsec.types, b->nsec.types);
689
5d45a880
TG
690 case DNS_TYPE_NSEC3:
691 return a->nsec3.algorithm == b->nsec3.algorithm &&
692 a->nsec3.flags == b->nsec3.flags &&
693 a->nsec3.iterations == b->nsec3.iterations &&
694 a->nsec3.salt_size == b->nsec3.salt_size &&
695 memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
696 memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
697 bitmap_equal(a->nsec3.types, b->nsec3.types);
698
48d45d2b
ZJS
699 case DNS_TYPE_TLSA:
700 return a->tlsa.cert_usage == b->tlsa.cert_usage &&
701 a->tlsa.selector == b->tlsa.selector &&
702 a->tlsa.matching_type == b->tlsa.matching_type &&
703 a->tlsa.data_size == b->tlsa.data_size &&
704 memcmp(a->tlsa.data, b->tlsa.data, a->tlsa.data_size) == 0;
705
2d4c5cbc 706 default:
322345fd
LP
707 return a->generic.size == b->generic.size &&
708 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
2d4c5cbc 709 }
322345fd
LP
710}
711
0dae31d4
ZJS
712static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
713 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
714 char *s;
715 char NS = latitude >= 1U<<31 ? 'N' : 'S';
716 char EW = longitude >= 1U<<31 ? 'E' : 'W';
717
718 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
719 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
720 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
721 double siz = (size >> 4) * exp10((double) (size & 0xF));
722 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
723 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
724
725 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
726 (lat / 60000 / 60),
727 (lat / 60000) % 60,
728 (lat % 60000) / 1000.,
729 NS,
730 (lon / 60000 / 60),
731 (lon / 60000) % 60,
732 (lon % 60000) / 1000.,
733 EW,
734 alt / 100.,
735 siz / 100.,
736 hor / 100.,
737 ver / 100.) < 0)
738 return NULL;
739
740 return s;
741}
742
7c6423e1
TG
743static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
744 struct tm tm;
745
746 assert(buf);
747 assert(l > strlen("YYYYMMDDHHmmSS"));
748
749 if (!gmtime_r(&sec, &tm))
750 return -EINVAL;
751
752 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
753 return -EINVAL;
754
755 return 0;
756}
757
50f1e641
TG
758static char *format_types(Bitmap *types) {
759 _cleanup_strv_free_ char **strv = NULL;
760 _cleanup_free_ char *str = NULL;
cb57dd41 761 Iterator i;
50f1e641
TG
762 unsigned type;
763 int r;
764
cb57dd41 765 BITMAP_FOREACH(type, types, i) {
50f1e641 766 if (dns_type_to_string(type)) {
2c1fb4f7 767 r = strv_extend(&strv, dns_type_to_string(type));
50f1e641
TG
768 if (r < 0)
769 return NULL;
770 } else {
771 char *t;
772
773 r = asprintf(&t, "TYPE%u", type);
774 if (r < 0)
775 return NULL;
776
2c1fb4f7 777 r = strv_consume(&strv, t);
50f1e641
TG
778 if (r < 0)
779 return NULL;
780 }
781 }
782
783 str = strv_join(strv, " ");
784 if (!str)
785 return NULL;
786
787 return strjoin("( ", str, " )", NULL);
788}
789
2001c805
LP
790static char *format_txt(DnsTxtItem *first) {
791 DnsTxtItem *i;
792 size_t c = 1;
793 char *p, *s;
794
795 LIST_FOREACH(items, i, first)
796 c += i->length * 4 + 3;
797
798 p = s = new(char, c);
799 if (!s)
800 return NULL;
801
802 LIST_FOREACH(items, i, first) {
803 size_t j;
804
805 if (i != first)
806 *(p++) = ' ';
807
808 *(p++) = '"';
809
810 for (j = 0; j < i->length; j++) {
811 if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) {
812 *(p++) = '\\';
813 *(p++) = '0' + (i->data[j] / 100);
814 *(p++) = '0' + ((i->data[j] / 10) % 10);
815 *(p++) = '0' + (i->data[j] % 10);
816 } else
817 *(p++) = i->data[j];
818 }
819
820 *(p++) = '"';
821 }
822
823 *p = 0;
824 return s;
825}
826
7b50eb2e 827const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
8db0d2f5 828 _cleanup_free_ char *k = NULL, *t = NULL;
2d4c5cbc
LP
829 char *s;
830 int r;
322345fd 831
2d4c5cbc 832 assert(rr);
322345fd 833
7b50eb2e
LP
834 if (rr->to_string)
835 return rr->to_string;
836
2d4c5cbc
LP
837 r = dns_resource_key_to_string(rr->key, &k);
838 if (r < 0)
7b50eb2e 839 return NULL;
322345fd 840
0dae31d4 841 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
322345fd 842
9c92ce6d
LP
843 case DNS_TYPE_SRV:
844 r = asprintf(&s, "%s %u %u %u %s",
845 k,
846 rr->srv.priority,
847 rr->srv.weight,
848 rr->srv.port,
849 strna(rr->srv.name));
850 if (r < 0)
7b50eb2e 851 return NULL;
9c92ce6d
LP
852 break;
853
2d4c5cbc
LP
854 case DNS_TYPE_PTR:
855 case DNS_TYPE_NS:
856 case DNS_TYPE_CNAME:
8ac4e9e1 857 case DNS_TYPE_DNAME:
2d4c5cbc
LP
858 s = strjoin(k, " ", rr->ptr.name, NULL);
859 if (!s)
7b50eb2e 860 return NULL;
322345fd 861
2d4c5cbc 862 break;
322345fd 863
2d4c5cbc
LP
864 case DNS_TYPE_HINFO:
865 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
866 if (!s)
7b50eb2e 867 return NULL;
2d4c5cbc 868 break;
322345fd 869
9de3e329 870 case DNS_TYPE_SPF: /* exactly the same as TXT */
8db0d2f5 871 case DNS_TYPE_TXT:
2001c805 872 t = format_txt(rr->txt.items);
2e276efc 873 if (!t)
7b50eb2e 874 return NULL;
2e276efc
ZJS
875
876 s = strjoin(k, " ", t, NULL);
877 if (!s)
7b50eb2e 878 return NULL;
2e276efc 879 break;
2e276efc 880
2d4c5cbc
LP
881 case DNS_TYPE_A: {
882 _cleanup_free_ char *x = NULL;
322345fd 883
2d4c5cbc
LP
884 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
885 if (r < 0)
7b50eb2e 886 return NULL;
322345fd 887
2d4c5cbc
LP
888 s = strjoin(k, " ", x, NULL);
889 if (!s)
7b50eb2e 890 return NULL;
2d4c5cbc
LP
891 break;
892 }
322345fd 893
8db0d2f5
ZJS
894 case DNS_TYPE_AAAA:
895 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
2d4c5cbc 896 if (r < 0)
7b50eb2e 897 return NULL;
322345fd 898
8db0d2f5 899 s = strjoin(k, " ", t, NULL);
2d4c5cbc 900 if (!s)
7b50eb2e 901 return NULL;
2d4c5cbc 902 break;
322345fd 903
2d4c5cbc
LP
904 case DNS_TYPE_SOA:
905 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
906 k,
907 strna(rr->soa.mname),
908 strna(rr->soa.rname),
909 rr->soa.serial,
910 rr->soa.refresh,
911 rr->soa.retry,
912 rr->soa.expire,
913 rr->soa.minimum);
914 if (r < 0)
7b50eb2e 915 return NULL;
2d4c5cbc
LP
916 break;
917
946c7094
ZJS
918 case DNS_TYPE_MX:
919 r = asprintf(&s, "%s %u %s",
920 k,
921 rr->mx.priority,
922 rr->mx.exchange);
923 if (r < 0)
7b50eb2e 924 return NULL;
946c7094
ZJS
925 break;
926
8db0d2f5 927 case DNS_TYPE_LOC:
0dae31d4
ZJS
928 assert(rr->loc.version == 0);
929
8db0d2f5
ZJS
930 t = format_location(rr->loc.latitude,
931 rr->loc.longitude,
932 rr->loc.altitude,
933 rr->loc.size,
934 rr->loc.horiz_pre,
935 rr->loc.vert_pre);
936 if (!t)
7b50eb2e 937 return NULL;
0dae31d4 938
8db0d2f5 939 s = strjoin(k, " ", t, NULL);
0dae31d4 940 if (!s)
7b50eb2e 941 return NULL;
0dae31d4 942 break;
0dae31d4 943
abf126a3
TG
944 case DNS_TYPE_DS:
945 t = hexmem(rr->ds.digest, rr->ds.digest_size);
946 if (!t)
7b50eb2e 947 return NULL;
abf126a3
TG
948
949 r = asprintf(&s, "%s %u %u %u %s",
950 k,
951 rr->ds.key_tag,
952 rr->ds.algorithm,
953 rr->ds.digest_type,
954 t);
955 if (r < 0)
7b50eb2e 956 return NULL;
abf126a3
TG
957 break;
958
8db0d2f5 959 case DNS_TYPE_SSHFP:
549c1a25 960 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
8db0d2f5 961 if (!t)
7b50eb2e 962 return NULL;
42cc2eeb
LP
963
964 r = asprintf(&s, "%s %u %u %s",
965 k,
966 rr->sshfp.algorithm,
967 rr->sshfp.fptype,
8db0d2f5 968 t);
42cc2eeb 969 if (r < 0)
7b50eb2e 970 return NULL;
42cc2eeb 971 break;
42cc2eeb 972
ff3d6560 973 case DNS_TYPE_DNSKEY: {
8e54f5d9 974 _cleanup_free_ char *alg = NULL;
99e5ca6d
ZJS
975 char *ss;
976 int n, n1;
fc8eec10
ZJS
977 uint16_t key_tag;
978
979 key_tag = dnssec_keytag(rr, true);
ff3d6560 980
8e54f5d9
LP
981 r = dnssec_algorithm_to_string_alloc(rr->dnskey.algorithm, &alg);
982 if (r < 0)
983 return NULL;
ff3d6560 984
99e5ca6d 985 r = asprintf(&s, "%s %n%u %u %s %n",
8db0d2f5 986 k,
99e5ca6d 987 &n1,
f91dc240
LP
988 rr->dnskey.flags,
989 rr->dnskey.protocol,
8e54f5d9 990 alg,
d7671a3e 991 &n);
8db0d2f5 992 if (r < 0)
7b50eb2e 993 return NULL;
d7671a3e
ZJS
994
995 r = base64_append(&s, n,
996 rr->dnskey.key, rr->dnskey.key_size,
997 8, columns());
998 if (r < 0)
999 return NULL;
1000
99e5ca6d 1001 r = asprintf(&ss, "%s\n"
fc8eec10
ZJS
1002 "%*s-- Flags:%s%s%s\n"
1003 "%*s-- Key tag: %u",
99e5ca6d
ZJS
1004 s,
1005 n1, "",
1006 rr->dnskey.flags & DNSKEY_FLAG_SEP ? " SEP" : "",
1007 rr->dnskey.flags & DNSKEY_FLAG_REVOKE ? " REVOKE" : "",
fc8eec10
ZJS
1008 rr->dnskey.flags & DNSKEY_FLAG_ZONE_KEY ? " ZONE_KEY" : "",
1009 n1, "",
1010 key_tag);
99e5ca6d
ZJS
1011 if (r < 0)
1012 return NULL;
1013 free(s);
1014 s = ss;
1015
8db0d2f5 1016 break;
ff3d6560 1017 }
2d4c5cbc 1018
151226ab 1019 case DNS_TYPE_RRSIG: {
8e54f5d9 1020 _cleanup_free_ char *alg = NULL;
7c6423e1 1021 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
8e54f5d9 1022 const char *type;
d7671a3e 1023 int n;
151226ab
ZJS
1024
1025 type = dns_type_to_string(rr->rrsig.type_covered);
8e54f5d9
LP
1026
1027 r = dnssec_algorithm_to_string_alloc(rr->rrsig.algorithm, &alg);
1028 if (r < 0)
1029 return NULL;
151226ab 1030
7c6423e1
TG
1031 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
1032 if (r < 0)
7b50eb2e 1033 return NULL;
7c6423e1
TG
1034
1035 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
1036 if (r < 0)
7b50eb2e 1037 return NULL;
7c6423e1 1038
151226ab
ZJS
1039 /* TYPE?? follows
1040 * http://tools.ietf.org/html/rfc3597#section-5 */
1041
d7671a3e 1042 r = asprintf(&s, "%s %s%.*u %s %u %u %s %s %u %s %n",
151226ab
ZJS
1043 k,
1044 type ?: "TYPE",
1045 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
8e54f5d9 1046 alg,
151226ab
ZJS
1047 rr->rrsig.labels,
1048 rr->rrsig.original_ttl,
7c6423e1
TG
1049 expiration,
1050 inception,
151226ab
ZJS
1051 rr->rrsig.key_tag,
1052 rr->rrsig.signer,
d7671a3e 1053 &n);
151226ab 1054 if (r < 0)
7b50eb2e 1055 return NULL;
d7671a3e
ZJS
1056
1057 r = base64_append(&s, n,
1058 rr->rrsig.signature, rr->rrsig.signature_size,
1059 8, columns());
1060 if (r < 0)
1061 return NULL;
1062
151226ab
ZJS
1063 break;
1064 }
1065
50f1e641
TG
1066 case DNS_TYPE_NSEC:
1067 t = format_types(rr->nsec.types);
1068 if (!t)
7b50eb2e 1069 return NULL;
50f1e641
TG
1070
1071 r = asprintf(&s, "%s %s %s",
1072 k,
1073 rr->nsec.next_domain_name,
1074 t);
1075 if (r < 0)
7b50eb2e 1076 return NULL;
50f1e641
TG
1077 break;
1078
5d45a880
TG
1079 case DNS_TYPE_NSEC3: {
1080 _cleanup_free_ char *salt = NULL, *hash = NULL;
1081
f5430a3e 1082 if (rr->nsec3.salt_size > 0) {
5d45a880
TG
1083 salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
1084 if (!salt)
7b50eb2e 1085 return NULL;
5d45a880
TG
1086 }
1087
1088 hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
1089 if (!hash)
7b50eb2e 1090 return NULL;
5d45a880
TG
1091
1092 t = format_types(rr->nsec3.types);
1093 if (!t)
7b50eb2e 1094 return NULL;
5d45a880
TG
1095
1096 r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
1097 k,
1098 rr->nsec3.algorithm,
1099 rr->nsec3.flags,
1100 rr->nsec3.iterations,
f5430a3e 1101 rr->nsec3.salt_size > 0 ? salt : "-",
5d45a880
TG
1102 hash,
1103 t);
1104 if (r < 0)
7b50eb2e 1105 return NULL;
5d45a880
TG
1106
1107 break;
1108 }
1109
48d45d2b 1110 case DNS_TYPE_TLSA: {
cfb90da3
ZJS
1111 const char *cert_usage, *selector, *matching_type;
1112 char *ss;
48d45d2b
ZJS
1113 int n;
1114
cfb90da3
ZJS
1115 cert_usage = tlsa_cert_usage_to_string(rr->tlsa.cert_usage);
1116 selector = tlsa_selector_to_string(rr->tlsa.selector);
1117 matching_type = tlsa_matching_type_to_string(rr->tlsa.matching_type);
1118
48d45d2b
ZJS
1119 r = asprintf(&s, "%s %u %u %u %n",
1120 k,
1121 rr->tlsa.cert_usage,
1122 rr->tlsa.selector,
1123 rr->tlsa.matching_type,
1124 &n);
1125 if (r < 0)
1126 return NULL;
1127
1128 r = base64_append(&s, n,
1129 rr->tlsa.data, rr->tlsa.data_size,
1130 8, columns());
1131 if (r < 0)
1132 return NULL;
cfb90da3
ZJS
1133
1134 r = asprintf(&ss, "%s\n"
1135 "%*s-- Cert. usage: %s\n"
1136 "%*s-- Selector: %s\n"
1137 "%*s-- Matching type: %s",
1138 s,
1139 n - 6, "", cert_usage,
1140 n - 6, "", selector,
1141 n - 6, "", matching_type);
1142 if (r < 0)
1143 return NULL;
1144 free(s);
1145 s = ss;
1146
48d45d2b
ZJS
1147 break;
1148 }
1149
d93a16b8
ZJS
1150 case DNS_TYPE_OPENPGPKEY: {
1151 int n;
1152
1153 r = asprintf(&s, "%s %n",
1154 k,
1155 &n);
1156 if (r < 0)
1157 return NULL;
1158
1159 r = base64_append(&s, n,
1160 rr->generic.data, rr->generic.size,
1161 8, columns());
1162 if (r < 0)
1163 return NULL;
1164 break;
1165 }
1166
8db0d2f5
ZJS
1167 default:
1168 t = hexmem(rr->generic.data, rr->generic.size);
1169 if (!t)
7b50eb2e 1170 return NULL;
8db0d2f5 1171
6af47493 1172 /* Format as documented in RFC 3597, Section 5 */
f5430a3e 1173 r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
d23a27a9 1174 if (r < 0)
7b50eb2e 1175 return NULL;
2d4c5cbc 1176 break;
8db0d2f5 1177 }
2d4c5cbc 1178
7b50eb2e
LP
1179 rr->to_string = s;
1180 return s;
2d4c5cbc 1181}
322345fd 1182
a8812dd7
LP
1183int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {
1184
1185 DnsPacket packet = {
1186 .n_ref = 1,
1187 .protocol = DNS_PROTOCOL_DNS,
1188 .on_stack = true,
1189 .refuse_compression = true,
1190 .canonical_form = canonical,
1191 };
1192
1193 size_t start, rds;
1194 int r;
1195
1196 assert(rr);
1197
1198 /* Generates the RR in wire-format, optionally in the
1199 * canonical form as discussed in the DNSSEC RFC 4034, Section
1200 * 6.2. We allocate a throw-away DnsPacket object on the stack
1201 * here, because we need some book-keeping for memory
1202 * management, and can reuse the DnsPacket serializer, that
1203 * can generate the canonical form, too, but also knows label
1204 * compression and suchlike. */
1205
1206 if (rr->wire_format && rr->wire_format_canonical == canonical)
1207 return 0;
1208
1209 r = dns_packet_append_rr(&packet, rr, &start, &rds);
1210 if (r < 0)
1211 return r;
1212
1213 assert(start == 0);
1214 assert(packet._data);
1215
1216 free(rr->wire_format);
1217 rr->wire_format = packet._data;
1218 rr->wire_format_size = packet.size;
1219 rr->wire_format_rdata_offset = rds;
1220 rr->wire_format_canonical = canonical;
1221
1222 packet._data = NULL;
1223 dns_packet_unref(&packet);
1224
1225 return 0;
1226}
1227
97c67192
LP
1228int dns_resource_record_signer(DnsResourceRecord *rr, const char **ret) {
1229 const char *n;
1230 int r;
1231
1232 assert(rr);
1233 assert(ret);
1234
1235 /* Returns the RRset's signer, if it is known. */
1236
1237 if (rr->n_skip_labels_signer == (unsigned) -1)
1238 return -ENODATA;
1239
1240 n = DNS_RESOURCE_KEY_NAME(rr->key);
1241 r = dns_name_skip(n, rr->n_skip_labels_signer, &n);
1242 if (r < 0)
1243 return r;
1244 if (r == 0)
1245 return -EINVAL;
1246
1247 *ret = n;
1248 return 0;
1249}
1250
1251int dns_resource_record_source(DnsResourceRecord *rr, const char **ret) {
1252 const char *n;
1253 int r;
1254
1255 assert(rr);
1256 assert(ret);
1257
1258 /* Returns the RRset's synthesizing source, if it is known. */
1259
1260 if (rr->n_skip_labels_source == (unsigned) -1)
1261 return -ENODATA;
1262
1263 n = DNS_RESOURCE_KEY_NAME(rr->key);
1264 r = dns_name_skip(n, rr->n_skip_labels_source, &n);
1265 if (r < 0)
1266 return r;
1267 if (r == 0)
1268 return -EINVAL;
1269
1270 *ret = n;
1271 return 0;
1272}
1273
1274int dns_resource_record_is_signer(DnsResourceRecord *rr, const char *zone) {
1275 const char *signer;
1276 int r;
1277
ab481675
LP
1278 assert(rr);
1279
97c67192
LP
1280 r = dns_resource_record_signer(rr, &signer);
1281 if (r < 0)
1282 return r;
1283
1284 return dns_name_equal(zone, signer);
1285}
1286
ab481675
LP
1287int dns_resource_record_is_synthetic(DnsResourceRecord *rr) {
1288 int r;
1289
1290 assert(rr);
1291
1292 /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */
1293
1294 if (rr->n_skip_labels_source == (unsigned) -1)
1295 return -ENODATA;
1296
1297 if (rr->n_skip_labels_source == 0)
1298 return 0;
1299
1300 if (rr->n_skip_labels_source > 1)
1301 return 1;
1302
1303 r = dns_name_startswith(DNS_RESOURCE_KEY_NAME(rr->key), "*");
1304 if (r < 0)
1305 return r;
1306
1307 return !r;
1308}
1309
c9c72065
LP
1310static void dns_resource_record_hash_func(const void *i, struct siphash *state) {
1311 const DnsResourceRecord *rr = i;
1312
1313 assert(rr);
1314
1315 dns_resource_key_hash_func(rr->key, state);
1316
1317 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
1318
1319 case DNS_TYPE_SRV:
1320 siphash24_compress(&rr->srv.priority, sizeof(rr->srv.priority), state);
1321 siphash24_compress(&rr->srv.weight, sizeof(rr->srv.weight), state);
1322 siphash24_compress(&rr->srv.port, sizeof(rr->srv.port), state);
1323 dns_name_hash_func(rr->srv.name, state);
1324 break;
1325
1326 case DNS_TYPE_PTR:
1327 case DNS_TYPE_NS:
1328 case DNS_TYPE_CNAME:
1329 case DNS_TYPE_DNAME:
1330 dns_name_hash_func(rr->ptr.name, state);
1331 break;
1332
1333 case DNS_TYPE_HINFO:
1334 string_hash_func(rr->hinfo.cpu, state);
1335 string_hash_func(rr->hinfo.os, state);
1336 break;
1337
1338 case DNS_TYPE_TXT:
1339 case DNS_TYPE_SPF: {
1340 DnsTxtItem *j;
1341
1342 LIST_FOREACH(items, j, rr->txt.items) {
1343 siphash24_compress(j->data, j->length, state);
1344
d5115566
LP
1345 /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab"
1346 * followed by "". */
1347 siphash24_compress_byte(0, state);
c9c72065
LP
1348 }
1349 break;
1350 }
1351
1352 case DNS_TYPE_A:
1353 siphash24_compress(&rr->a.in_addr, sizeof(rr->a.in_addr), state);
1354 break;
1355
1356 case DNS_TYPE_AAAA:
1357 siphash24_compress(&rr->aaaa.in6_addr, sizeof(rr->aaaa.in6_addr), state);
1358 break;
1359
1360 case DNS_TYPE_SOA:
1361 dns_name_hash_func(rr->soa.mname, state);
1362 dns_name_hash_func(rr->soa.rname, state);
1363 siphash24_compress(&rr->soa.serial, sizeof(rr->soa.serial), state);
1364 siphash24_compress(&rr->soa.refresh, sizeof(rr->soa.refresh), state);
1365 siphash24_compress(&rr->soa.retry, sizeof(rr->soa.retry), state);
1366 siphash24_compress(&rr->soa.expire, sizeof(rr->soa.expire), state);
1367 siphash24_compress(&rr->soa.minimum, sizeof(rr->soa.minimum), state);
1368 break;
1369
1370 case DNS_TYPE_MX:
1371 siphash24_compress(&rr->mx.priority, sizeof(rr->mx.priority), state);
1372 dns_name_hash_func(rr->mx.exchange, state);
1373 break;
1374
1375 case DNS_TYPE_LOC:
1376 siphash24_compress(&rr->loc.version, sizeof(rr->loc.version), state);
1377 siphash24_compress(&rr->loc.size, sizeof(rr->loc.size), state);
1378 siphash24_compress(&rr->loc.horiz_pre, sizeof(rr->loc.horiz_pre), state);
1379 siphash24_compress(&rr->loc.vert_pre, sizeof(rr->loc.vert_pre), state);
1380 siphash24_compress(&rr->loc.latitude, sizeof(rr->loc.latitude), state);
1381 siphash24_compress(&rr->loc.longitude, sizeof(rr->loc.longitude), state);
1382 siphash24_compress(&rr->loc.altitude, sizeof(rr->loc.altitude), state);
1383 break;
1384
1385 case DNS_TYPE_SSHFP:
1386 siphash24_compress(&rr->sshfp.algorithm, sizeof(rr->sshfp.algorithm), state);
1387 siphash24_compress(&rr->sshfp.fptype, sizeof(rr->sshfp.fptype), state);
1388 siphash24_compress(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, state);
1389 break;
1390
1391 case DNS_TYPE_DNSKEY:
1392 siphash24_compress(&rr->dnskey.flags, sizeof(rr->dnskey.flags), state);
1393 siphash24_compress(&rr->dnskey.protocol, sizeof(rr->dnskey.protocol), state);
1394 siphash24_compress(&rr->dnskey.algorithm, sizeof(rr->dnskey.algorithm), state);
1395 siphash24_compress(rr->dnskey.key, rr->dnskey.key_size, state);
1396 break;
1397
1398 case DNS_TYPE_RRSIG:
1399 siphash24_compress(&rr->rrsig.type_covered, sizeof(rr->rrsig.type_covered), state);
1400 siphash24_compress(&rr->rrsig.algorithm, sizeof(rr->rrsig.algorithm), state);
1401 siphash24_compress(&rr->rrsig.labels, sizeof(rr->rrsig.labels), state);
1402 siphash24_compress(&rr->rrsig.original_ttl, sizeof(rr->rrsig.original_ttl), state);
1403 siphash24_compress(&rr->rrsig.expiration, sizeof(rr->rrsig.expiration), state);
1404 siphash24_compress(&rr->rrsig.inception, sizeof(rr->rrsig.inception), state);
1405 siphash24_compress(&rr->rrsig.key_tag, sizeof(rr->rrsig.key_tag), state);
1406 dns_name_hash_func(rr->rrsig.signer, state);
1407 siphash24_compress(rr->rrsig.signature, rr->rrsig.signature_size, state);
1408 break;
1409
1410 case DNS_TYPE_NSEC:
1411 dns_name_hash_func(rr->nsec.next_domain_name, state);
1412 /* FIXME: we leave out the type bitmap here. Hash
1413 * would be better if we'd take it into account
1414 * too. */
1415 break;
1416
1417 case DNS_TYPE_DS:
1418 siphash24_compress(&rr->ds.key_tag, sizeof(rr->ds.key_tag), state);
1419 siphash24_compress(&rr->ds.algorithm, sizeof(rr->ds.algorithm), state);
1420 siphash24_compress(&rr->ds.digest_type, sizeof(rr->ds.digest_type), state);
1421 siphash24_compress(rr->ds.digest, rr->ds.digest_size, state);
1422 break;
1423
1424 case DNS_TYPE_NSEC3:
1425 siphash24_compress(&rr->nsec3.algorithm, sizeof(rr->nsec3.algorithm), state);
1426 siphash24_compress(&rr->nsec3.flags, sizeof(rr->nsec3.flags), state);
1427 siphash24_compress(&rr->nsec3.iterations, sizeof(rr->nsec3.iterations), state);
1428 siphash24_compress(rr->nsec3.salt, rr->nsec3.salt_size, state);
1429 siphash24_compress(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, state);
1430 /* FIXME: We leave the bitmaps out */
1431 break;
48d45d2b
ZJS
1432
1433 case DNS_TYPE_TLSA:
1434 siphash24_compress(&rr->tlsa.cert_usage, sizeof(rr->tlsa.cert_usage), state);
1435 siphash24_compress(&rr->tlsa.selector, sizeof(rr->tlsa.selector), state);
1436 siphash24_compress(&rr->tlsa.matching_type, sizeof(rr->tlsa.matching_type), state);
1437 siphash24_compress(&rr->tlsa.data, rr->tlsa.data_size, state);
1438 break;
c9c72065 1439
d93a16b8 1440 case DNS_TYPE_OPENPGPKEY:
c9c72065
LP
1441 default:
1442 siphash24_compress(rr->generic.data, rr->generic.size, state);
1443 break;
1444 }
1445}
1446
1447static int dns_resource_record_compare_func(const void *a, const void *b) {
1448 const DnsResourceRecord *x = a, *y = b;
1449 int ret;
1450
1451 ret = dns_resource_key_compare_func(x->key, y->key);
1452 if (ret != 0)
1453 return ret;
1454
1455 if (dns_resource_record_equal(x, y))
1456 return 0;
1457
1458 /* This is a bit dirty, we don't implement proper odering, but
1459 * the hashtable doesn't need ordering anyway, hence we don't
1460 * care. */
1461 return x < y ? -1 : 1;
1462}
1463
1464const struct hash_ops dns_resource_record_hash_ops = {
1465 .hash = dns_resource_record_hash_func,
1466 .compare = dns_resource_record_compare_func,
1467};
1468
2001c805
LP
1469DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
1470 DnsTxtItem *n;
1471
1472 if (!i)
1473 return NULL;
1474
1475 n = i->items_next;
1476
1477 free(i);
1478 return dns_txt_item_free_all(n);
1479}
1480
1481bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
1482
4d247a6c
LP
1483 if (a == b)
1484 return true;
1485
2001c805
LP
1486 if (!a != !b)
1487 return false;
1488
1489 if (!a)
1490 return true;
1491
1492 if (a->length != b->length)
1493 return false;
1494
1495 if (memcmp(a->data, b->data, a->length) != 0)
1496 return false;
1497
1498 return dns_txt_item_equal(a->items_next, b->items_next);
1499}
8730bccf
LP
1500
1501static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
6f717d08 1502 /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
8730bccf
LP
1503 [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
1504 [DNSSEC_ALGORITHM_DH] = "DH",
1505 [DNSSEC_ALGORITHM_DSA] = "DSA",
1506 [DNSSEC_ALGORITHM_ECC] = "ECC",
1507 [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
1508 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1",
1509 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1",
1510 [DNSSEC_ALGORITHM_RSASHA256] = "RSASHA256",
1511 [DNSSEC_ALGORITHM_RSASHA512] = "RSASHA512",
6f717d08
LP
1512 [DNSSEC_ALGORITHM_ECC_GOST] = "ECC-GOST",
1513 [DNSSEC_ALGORITHM_ECDSAP256SHA256] = "ECDSAP256SHA256",
1514 [DNSSEC_ALGORITHM_ECDSAP384SHA384] = "ECDSAP384SHA384",
8730bccf
LP
1515 [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
1516 [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
1517 [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
1518};
8e54f5d9 1519DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm, int, 255);
8730bccf
LP
1520
1521static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = {
6f717d08
LP
1522 /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
1523 [DNSSEC_DIGEST_SHA1] = "SHA-1",
1524 [DNSSEC_DIGEST_SHA256] = "SHA-256",
1525 [DNSSEC_DIGEST_GOST_R_34_11_94] = "GOST_R_34.11-94",
1526 [DNSSEC_DIGEST_SHA384] = "SHA-384",
8730bccf 1527};
8e54f5d9 1528DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest, int, 255);