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