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