]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-rr.c
resolved: TLSA 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
9de3e329 494 default:
faa133f3 495 free(rr->generic.data);
9de3e329 496 }
322345fd 497
a8812dd7 498 free(rr->wire_format);
faa133f3
LP
499 dns_resource_key_unref(rr->key);
500 }
322345fd 501
7b50eb2e 502 free(rr->to_string);
faa133f3 503 free(rr);
322345fd 504
322345fd
LP
505 return NULL;
506}
507
623a4c97
LP
508int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
509 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
510 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
511 _cleanup_free_ char *ptr = NULL;
512 int r;
513
514 assert(ret);
515 assert(address);
516 assert(hostname);
517
518 r = dns_name_reverse(family, address, &ptr);
519 if (r < 0)
520 return r;
521
522 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
523 if (!key)
524 return -ENOMEM;
525
526 ptr = NULL;
527
528 rr = dns_resource_record_new(key);
529 if (!rr)
530 return -ENOMEM;
531
532 rr->ptr.name = strdup(hostname);
533 if (!rr->ptr.name)
534 return -ENOMEM;
535
536 *ret = rr;
537 rr = NULL;
538
539 return 0;
540}
541
78c6a153
LP
542int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
543 DnsResourceRecord *rr;
544
545 assert(ret);
546 assert(address);
547 assert(family);
548
549 if (family == AF_INET) {
550
551 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
552 if (!rr)
553 return -ENOMEM;
554
555 rr->a.in_addr = address->in;
556
557 } else if (family == AF_INET6) {
558
559 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
560 if (!rr)
561 return -ENOMEM;
562
563 rr->aaaa.in6_addr = address->in6;
564 } else
565 return -EAFNOSUPPORT;
566
567 *ret = rr;
568
569 return 0;
570}
571
322345fd
LP
572int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
573 int r;
574
575 assert(a);
576 assert(b);
577
4d247a6c
LP
578 if (a == b)
579 return 1;
580
faa133f3 581 r = dns_resource_key_equal(a->key, b->key);
322345fd
LP
582 if (r <= 0)
583 return r;
584
fd0b4602
LP
585 if (a->unparseable != b->unparseable)
586 return 0;
587
588 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
2d4c5cbc 589
9c92ce6d
LP
590 case DNS_TYPE_SRV:
591 r = dns_name_equal(a->srv.name, b->srv.name);
592 if (r <= 0)
593 return r;
594
595 return a->srv.priority == b->srv.priority &&
596 a->srv.weight == b->srv.weight &&
597 a->srv.port == b->srv.port;
598
2d4c5cbc
LP
599 case DNS_TYPE_PTR:
600 case DNS_TYPE_NS:
601 case DNS_TYPE_CNAME:
8ac4e9e1 602 case DNS_TYPE_DNAME:
322345fd 603 return dns_name_equal(a->ptr.name, b->ptr.name);
2d4c5cbc
LP
604
605 case DNS_TYPE_HINFO:
606 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
607 strcaseeq(a->hinfo.os, b->hinfo.os);
608
9de3e329 609 case DNS_TYPE_SPF: /* exactly the same as TXT */
0f84a72e 610 case DNS_TYPE_TXT:
2001c805 611 return dns_txt_item_equal(a->txt.items, b->txt.items);
2e276efc 612
2d4c5cbc 613 case DNS_TYPE_A:
322345fd 614 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
2d4c5cbc
LP
615
616 case DNS_TYPE_AAAA:
322345fd 617 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
2d4c5cbc
LP
618
619 case DNS_TYPE_SOA:
7e8e0422
LP
620 r = dns_name_equal(a->soa.mname, b->soa.mname);
621 if (r <= 0)
622 return r;
623 r = dns_name_equal(a->soa.rname, b->soa.rname);
624 if (r <= 0)
625 return r;
626
627 return a->soa.serial == b->soa.serial &&
628 a->soa.refresh == b->soa.refresh &&
629 a->soa.retry == b->soa.retry &&
630 a->soa.expire == b->soa.expire &&
631 a->soa.minimum == b->soa.minimum;
9c92ce6d 632
946c7094
ZJS
633 case DNS_TYPE_MX:
634 if (a->mx.priority != b->mx.priority)
635 return 0;
636
637 return dns_name_equal(a->mx.exchange, b->mx.exchange);
638
0dae31d4
ZJS
639 case DNS_TYPE_LOC:
640 assert(a->loc.version == b->loc.version);
641
642 return a->loc.size == b->loc.size &&
643 a->loc.horiz_pre == b->loc.horiz_pre &&
644 a->loc.vert_pre == b->loc.vert_pre &&
645 a->loc.latitude == b->loc.latitude &&
646 a->loc.longitude == b->loc.longitude &&
647 a->loc.altitude == b->loc.altitude;
648
abf126a3
TG
649 case DNS_TYPE_DS:
650 return a->ds.key_tag == b->ds.key_tag &&
651 a->ds.algorithm == b->ds.algorithm &&
652 a->ds.digest_type == b->ds.digest_type &&
653 a->ds.digest_size == b->ds.digest_size &&
654 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
655
42cc2eeb
LP
656 case DNS_TYPE_SSHFP:
657 return a->sshfp.algorithm == b->sshfp.algorithm &&
658 a->sshfp.fptype == b->sshfp.fptype &&
549c1a25
TG
659 a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
660 memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
42cc2eeb 661
8db0d2f5 662 case DNS_TYPE_DNSKEY:
f91dc240
LP
663 return a->dnskey.flags == b->dnskey.flags &&
664 a->dnskey.protocol == b->dnskey.protocol &&
8db0d2f5
ZJS
665 a->dnskey.algorithm == b->dnskey.algorithm &&
666 a->dnskey.key_size == b->dnskey.key_size &&
667 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
668
151226ab
ZJS
669 case DNS_TYPE_RRSIG:
670 /* do the fast comparisons first */
03664a62
LN
671 if (a->rrsig.type_covered != b->rrsig.type_covered ||
672 a->rrsig.algorithm != b->rrsig.algorithm ||
673 a->rrsig.labels != b->rrsig.labels ||
674 a->rrsig.original_ttl != b->rrsig.original_ttl ||
675 a->rrsig.expiration != b->rrsig.expiration ||
676 a->rrsig.inception != b->rrsig.inception ||
677 a->rrsig.key_tag != b->rrsig.key_tag ||
151226ab
ZJS
678 a->rrsig.signature_size != b->rrsig.signature_size ||
679 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
680 return false;
681
682 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
683
50f1e641
TG
684 case DNS_TYPE_NSEC:
685 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
686 bitmap_equal(a->nsec.types, b->nsec.types);
687
5d45a880
TG
688 case DNS_TYPE_NSEC3:
689 return a->nsec3.algorithm == b->nsec3.algorithm &&
690 a->nsec3.flags == b->nsec3.flags &&
691 a->nsec3.iterations == b->nsec3.iterations &&
692 a->nsec3.salt_size == b->nsec3.salt_size &&
693 memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
694 memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
695 bitmap_equal(a->nsec3.types, b->nsec3.types);
696
48d45d2b
ZJS
697 case DNS_TYPE_TLSA:
698 return a->tlsa.cert_usage == b->tlsa.cert_usage &&
699 a->tlsa.selector == b->tlsa.selector &&
700 a->tlsa.matching_type == b->tlsa.matching_type &&
701 a->tlsa.data_size == b->tlsa.data_size &&
702 memcmp(a->tlsa.data, b->tlsa.data, a->tlsa.data_size) == 0;
703
2d4c5cbc 704 default:
322345fd
LP
705 return a->generic.size == b->generic.size &&
706 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
2d4c5cbc 707 }
322345fd
LP
708}
709
0dae31d4
ZJS
710static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
711 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
712 char *s;
713 char NS = latitude >= 1U<<31 ? 'N' : 'S';
714 char EW = longitude >= 1U<<31 ? 'E' : 'W';
715
716 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
717 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
718 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
719 double siz = (size >> 4) * exp10((double) (size & 0xF));
720 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
721 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
722
723 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
724 (lat / 60000 / 60),
725 (lat / 60000) % 60,
726 (lat % 60000) / 1000.,
727 NS,
728 (lon / 60000 / 60),
729 (lon / 60000) % 60,
730 (lon % 60000) / 1000.,
731 EW,
732 alt / 100.,
733 siz / 100.,
734 hor / 100.,
735 ver / 100.) < 0)
736 return NULL;
737
738 return s;
739}
740
7c6423e1
TG
741static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
742 struct tm tm;
743
744 assert(buf);
745 assert(l > strlen("YYYYMMDDHHmmSS"));
746
747 if (!gmtime_r(&sec, &tm))
748 return -EINVAL;
749
750 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
751 return -EINVAL;
752
753 return 0;
754}
755
50f1e641
TG
756static char *format_types(Bitmap *types) {
757 _cleanup_strv_free_ char **strv = NULL;
758 _cleanup_free_ char *str = NULL;
cb57dd41 759 Iterator i;
50f1e641
TG
760 unsigned type;
761 int r;
762
cb57dd41 763 BITMAP_FOREACH(type, types, i) {
50f1e641 764 if (dns_type_to_string(type)) {
2c1fb4f7 765 r = strv_extend(&strv, dns_type_to_string(type));
50f1e641
TG
766 if (r < 0)
767 return NULL;
768 } else {
769 char *t;
770
771 r = asprintf(&t, "TYPE%u", type);
772 if (r < 0)
773 return NULL;
774
2c1fb4f7 775 r = strv_consume(&strv, t);
50f1e641
TG
776 if (r < 0)
777 return NULL;
778 }
779 }
780
781 str = strv_join(strv, " ");
782 if (!str)
783 return NULL;
784
785 return strjoin("( ", str, " )", NULL);
786}
787
2001c805
LP
788static char *format_txt(DnsTxtItem *first) {
789 DnsTxtItem *i;
790 size_t c = 1;
791 char *p, *s;
792
793 LIST_FOREACH(items, i, first)
794 c += i->length * 4 + 3;
795
796 p = s = new(char, c);
797 if (!s)
798 return NULL;
799
800 LIST_FOREACH(items, i, first) {
801 size_t j;
802
803 if (i != first)
804 *(p++) = ' ';
805
806 *(p++) = '"';
807
808 for (j = 0; j < i->length; j++) {
809 if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) {
810 *(p++) = '\\';
811 *(p++) = '0' + (i->data[j] / 100);
812 *(p++) = '0' + ((i->data[j] / 10) % 10);
813 *(p++) = '0' + (i->data[j] % 10);
814 } else
815 *(p++) = i->data[j];
816 }
817
818 *(p++) = '"';
819 }
820
821 *p = 0;
822 return s;
823}
824
7b50eb2e 825const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
8db0d2f5 826 _cleanup_free_ char *k = NULL, *t = NULL;
2d4c5cbc
LP
827 char *s;
828 int r;
322345fd 829
2d4c5cbc 830 assert(rr);
322345fd 831
7b50eb2e
LP
832 if (rr->to_string)
833 return rr->to_string;
834
2d4c5cbc
LP
835 r = dns_resource_key_to_string(rr->key, &k);
836 if (r < 0)
7b50eb2e 837 return NULL;
322345fd 838
0dae31d4 839 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
322345fd 840
9c92ce6d
LP
841 case DNS_TYPE_SRV:
842 r = asprintf(&s, "%s %u %u %u %s",
843 k,
844 rr->srv.priority,
845 rr->srv.weight,
846 rr->srv.port,
847 strna(rr->srv.name));
848 if (r < 0)
7b50eb2e 849 return NULL;
9c92ce6d
LP
850 break;
851
2d4c5cbc
LP
852 case DNS_TYPE_PTR:
853 case DNS_TYPE_NS:
854 case DNS_TYPE_CNAME:
8ac4e9e1 855 case DNS_TYPE_DNAME:
2d4c5cbc
LP
856 s = strjoin(k, " ", rr->ptr.name, NULL);
857 if (!s)
7b50eb2e 858 return NULL;
322345fd 859
2d4c5cbc 860 break;
322345fd 861
2d4c5cbc
LP
862 case DNS_TYPE_HINFO:
863 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
864 if (!s)
7b50eb2e 865 return NULL;
2d4c5cbc 866 break;
322345fd 867
9de3e329 868 case DNS_TYPE_SPF: /* exactly the same as TXT */
8db0d2f5 869 case DNS_TYPE_TXT:
2001c805 870 t = format_txt(rr->txt.items);
2e276efc 871 if (!t)
7b50eb2e 872 return NULL;
2e276efc
ZJS
873
874 s = strjoin(k, " ", t, NULL);
875 if (!s)
7b50eb2e 876 return NULL;
2e276efc 877 break;
2e276efc 878
2d4c5cbc
LP
879 case DNS_TYPE_A: {
880 _cleanup_free_ char *x = NULL;
322345fd 881
2d4c5cbc
LP
882 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
883 if (r < 0)
7b50eb2e 884 return NULL;
322345fd 885
2d4c5cbc
LP
886 s = strjoin(k, " ", x, NULL);
887 if (!s)
7b50eb2e 888 return NULL;
2d4c5cbc
LP
889 break;
890 }
322345fd 891
8db0d2f5
ZJS
892 case DNS_TYPE_AAAA:
893 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
2d4c5cbc 894 if (r < 0)
7b50eb2e 895 return NULL;
322345fd 896
8db0d2f5 897 s = strjoin(k, " ", t, NULL);
2d4c5cbc 898 if (!s)
7b50eb2e 899 return NULL;
2d4c5cbc 900 break;
322345fd 901
2d4c5cbc
LP
902 case DNS_TYPE_SOA:
903 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
904 k,
905 strna(rr->soa.mname),
906 strna(rr->soa.rname),
907 rr->soa.serial,
908 rr->soa.refresh,
909 rr->soa.retry,
910 rr->soa.expire,
911 rr->soa.minimum);
912 if (r < 0)
7b50eb2e 913 return NULL;
2d4c5cbc
LP
914 break;
915
946c7094
ZJS
916 case DNS_TYPE_MX:
917 r = asprintf(&s, "%s %u %s",
918 k,
919 rr->mx.priority,
920 rr->mx.exchange);
921 if (r < 0)
7b50eb2e 922 return NULL;
946c7094
ZJS
923 break;
924
8db0d2f5 925 case DNS_TYPE_LOC:
0dae31d4
ZJS
926 assert(rr->loc.version == 0);
927
8db0d2f5
ZJS
928 t = format_location(rr->loc.latitude,
929 rr->loc.longitude,
930 rr->loc.altitude,
931 rr->loc.size,
932 rr->loc.horiz_pre,
933 rr->loc.vert_pre);
934 if (!t)
7b50eb2e 935 return NULL;
0dae31d4 936
8db0d2f5 937 s = strjoin(k, " ", t, NULL);
0dae31d4 938 if (!s)
7b50eb2e 939 return NULL;
0dae31d4 940 break;
0dae31d4 941
abf126a3
TG
942 case DNS_TYPE_DS:
943 t = hexmem(rr->ds.digest, rr->ds.digest_size);
944 if (!t)
7b50eb2e 945 return NULL;
abf126a3
TG
946
947 r = asprintf(&s, "%s %u %u %u %s",
948 k,
949 rr->ds.key_tag,
950 rr->ds.algorithm,
951 rr->ds.digest_type,
952 t);
953 if (r < 0)
7b50eb2e 954 return NULL;
abf126a3
TG
955 break;
956
8db0d2f5 957 case DNS_TYPE_SSHFP:
549c1a25 958 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
8db0d2f5 959 if (!t)
7b50eb2e 960 return NULL;
42cc2eeb
LP
961
962 r = asprintf(&s, "%s %u %u %s",
963 k,
964 rr->sshfp.algorithm,
965 rr->sshfp.fptype,
8db0d2f5 966 t);
42cc2eeb 967 if (r < 0)
7b50eb2e 968 return NULL;
42cc2eeb 969 break;
42cc2eeb 970
ff3d6560 971 case DNS_TYPE_DNSKEY: {
8e54f5d9 972 _cleanup_free_ char *alg = NULL;
d7671a3e 973 int n;
ff3d6560 974
8e54f5d9
LP
975 r = dnssec_algorithm_to_string_alloc(rr->dnskey.algorithm, &alg);
976 if (r < 0)
977 return NULL;
ff3d6560 978
d7671a3e 979 r = asprintf(&s, "%s %u %u %s %n",
8db0d2f5 980 k,
f91dc240
LP
981 rr->dnskey.flags,
982 rr->dnskey.protocol,
8e54f5d9 983 alg,
d7671a3e 984 &n);
8db0d2f5 985 if (r < 0)
7b50eb2e 986 return NULL;
d7671a3e
ZJS
987
988 r = base64_append(&s, n,
989 rr->dnskey.key, rr->dnskey.key_size,
990 8, columns());
991 if (r < 0)
992 return NULL;
993
8db0d2f5 994 break;
ff3d6560 995 }
2d4c5cbc 996
151226ab 997 case DNS_TYPE_RRSIG: {
8e54f5d9 998 _cleanup_free_ char *alg = NULL;
7c6423e1 999 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
8e54f5d9 1000 const char *type;
d7671a3e 1001 int n;
151226ab
ZJS
1002
1003 type = dns_type_to_string(rr->rrsig.type_covered);
8e54f5d9
LP
1004
1005 r = dnssec_algorithm_to_string_alloc(rr->rrsig.algorithm, &alg);
1006 if (r < 0)
1007 return NULL;
151226ab 1008
7c6423e1
TG
1009 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
1010 if (r < 0)
7b50eb2e 1011 return NULL;
7c6423e1
TG
1012
1013 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
1014 if (r < 0)
7b50eb2e 1015 return NULL;
7c6423e1 1016
151226ab
ZJS
1017 /* TYPE?? follows
1018 * http://tools.ietf.org/html/rfc3597#section-5 */
1019
d7671a3e 1020 r = asprintf(&s, "%s %s%.*u %s %u %u %s %s %u %s %n",
151226ab
ZJS
1021 k,
1022 type ?: "TYPE",
1023 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
8e54f5d9 1024 alg,
151226ab
ZJS
1025 rr->rrsig.labels,
1026 rr->rrsig.original_ttl,
7c6423e1
TG
1027 expiration,
1028 inception,
151226ab
ZJS
1029 rr->rrsig.key_tag,
1030 rr->rrsig.signer,
d7671a3e 1031 &n);
151226ab 1032 if (r < 0)
7b50eb2e 1033 return NULL;
d7671a3e
ZJS
1034
1035 r = base64_append(&s, n,
1036 rr->rrsig.signature, rr->rrsig.signature_size,
1037 8, columns());
1038 if (r < 0)
1039 return NULL;
1040
151226ab
ZJS
1041 break;
1042 }
1043
50f1e641
TG
1044 case DNS_TYPE_NSEC:
1045 t = format_types(rr->nsec.types);
1046 if (!t)
7b50eb2e 1047 return NULL;
50f1e641
TG
1048
1049 r = asprintf(&s, "%s %s %s",
1050 k,
1051 rr->nsec.next_domain_name,
1052 t);
1053 if (r < 0)
7b50eb2e 1054 return NULL;
50f1e641
TG
1055 break;
1056
5d45a880
TG
1057 case DNS_TYPE_NSEC3: {
1058 _cleanup_free_ char *salt = NULL, *hash = NULL;
1059
f5430a3e 1060 if (rr->nsec3.salt_size > 0) {
5d45a880
TG
1061 salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
1062 if (!salt)
7b50eb2e 1063 return NULL;
5d45a880
TG
1064 }
1065
1066 hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
1067 if (!hash)
7b50eb2e 1068 return NULL;
5d45a880
TG
1069
1070 t = format_types(rr->nsec3.types);
1071 if (!t)
7b50eb2e 1072 return NULL;
5d45a880
TG
1073
1074 r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
1075 k,
1076 rr->nsec3.algorithm,
1077 rr->nsec3.flags,
1078 rr->nsec3.iterations,
f5430a3e 1079 rr->nsec3.salt_size > 0 ? salt : "-",
5d45a880
TG
1080 hash,
1081 t);
1082 if (r < 0)
7b50eb2e 1083 return NULL;
5d45a880
TG
1084
1085 break;
1086 }
1087
48d45d2b
ZJS
1088 case DNS_TYPE_TLSA: {
1089 int n;
1090
1091 r = asprintf(&s, "%s %u %u %u %n",
1092 k,
1093 rr->tlsa.cert_usage,
1094 rr->tlsa.selector,
1095 rr->tlsa.matching_type,
1096 &n);
1097 if (r < 0)
1098 return NULL;
1099
1100 r = base64_append(&s, n,
1101 rr->tlsa.data, rr->tlsa.data_size,
1102 8, columns());
1103 if (r < 0)
1104 return NULL;
1105 break;
1106 }
1107
8db0d2f5
ZJS
1108 default:
1109 t = hexmem(rr->generic.data, rr->generic.size);
1110 if (!t)
7b50eb2e 1111 return NULL;
8db0d2f5 1112
6af47493 1113 /* Format as documented in RFC 3597, Section 5 */
f5430a3e 1114 r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
d23a27a9 1115 if (r < 0)
7b50eb2e 1116 return NULL;
2d4c5cbc 1117 break;
8db0d2f5 1118 }
2d4c5cbc 1119
7b50eb2e
LP
1120 rr->to_string = s;
1121 return s;
2d4c5cbc 1122}
322345fd 1123
a8812dd7
LP
1124int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {
1125
1126 DnsPacket packet = {
1127 .n_ref = 1,
1128 .protocol = DNS_PROTOCOL_DNS,
1129 .on_stack = true,
1130 .refuse_compression = true,
1131 .canonical_form = canonical,
1132 };
1133
1134 size_t start, rds;
1135 int r;
1136
1137 assert(rr);
1138
1139 /* Generates the RR in wire-format, optionally in the
1140 * canonical form as discussed in the DNSSEC RFC 4034, Section
1141 * 6.2. We allocate a throw-away DnsPacket object on the stack
1142 * here, because we need some book-keeping for memory
1143 * management, and can reuse the DnsPacket serializer, that
1144 * can generate the canonical form, too, but also knows label
1145 * compression and suchlike. */
1146
1147 if (rr->wire_format && rr->wire_format_canonical == canonical)
1148 return 0;
1149
1150 r = dns_packet_append_rr(&packet, rr, &start, &rds);
1151 if (r < 0)
1152 return r;
1153
1154 assert(start == 0);
1155 assert(packet._data);
1156
1157 free(rr->wire_format);
1158 rr->wire_format = packet._data;
1159 rr->wire_format_size = packet.size;
1160 rr->wire_format_rdata_offset = rds;
1161 rr->wire_format_canonical = canonical;
1162
1163 packet._data = NULL;
1164 dns_packet_unref(&packet);
1165
1166 return 0;
1167}
1168
97c67192
LP
1169int dns_resource_record_signer(DnsResourceRecord *rr, const char **ret) {
1170 const char *n;
1171 int r;
1172
1173 assert(rr);
1174 assert(ret);
1175
1176 /* Returns the RRset's signer, if it is known. */
1177
1178 if (rr->n_skip_labels_signer == (unsigned) -1)
1179 return -ENODATA;
1180
1181 n = DNS_RESOURCE_KEY_NAME(rr->key);
1182 r = dns_name_skip(n, rr->n_skip_labels_signer, &n);
1183 if (r < 0)
1184 return r;
1185 if (r == 0)
1186 return -EINVAL;
1187
1188 *ret = n;
1189 return 0;
1190}
1191
1192int dns_resource_record_source(DnsResourceRecord *rr, const char **ret) {
1193 const char *n;
1194 int r;
1195
1196 assert(rr);
1197 assert(ret);
1198
1199 /* Returns the RRset's synthesizing source, if it is known. */
1200
1201 if (rr->n_skip_labels_source == (unsigned) -1)
1202 return -ENODATA;
1203
1204 n = DNS_RESOURCE_KEY_NAME(rr->key);
1205 r = dns_name_skip(n, rr->n_skip_labels_source, &n);
1206 if (r < 0)
1207 return r;
1208 if (r == 0)
1209 return -EINVAL;
1210
1211 *ret = n;
1212 return 0;
1213}
1214
1215int dns_resource_record_is_signer(DnsResourceRecord *rr, const char *zone) {
1216 const char *signer;
1217 int r;
1218
ab481675
LP
1219 assert(rr);
1220
97c67192
LP
1221 r = dns_resource_record_signer(rr, &signer);
1222 if (r < 0)
1223 return r;
1224
1225 return dns_name_equal(zone, signer);
1226}
1227
ab481675
LP
1228int dns_resource_record_is_synthetic(DnsResourceRecord *rr) {
1229 int r;
1230
1231 assert(rr);
1232
1233 /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */
1234
1235 if (rr->n_skip_labels_source == (unsigned) -1)
1236 return -ENODATA;
1237
1238 if (rr->n_skip_labels_source == 0)
1239 return 0;
1240
1241 if (rr->n_skip_labels_source > 1)
1242 return 1;
1243
1244 r = dns_name_startswith(DNS_RESOURCE_KEY_NAME(rr->key), "*");
1245 if (r < 0)
1246 return r;
1247
1248 return !r;
1249}
1250
c9c72065
LP
1251static void dns_resource_record_hash_func(const void *i, struct siphash *state) {
1252 const DnsResourceRecord *rr = i;
1253
1254 assert(rr);
1255
1256 dns_resource_key_hash_func(rr->key, state);
1257
1258 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
1259
1260 case DNS_TYPE_SRV:
1261 siphash24_compress(&rr->srv.priority, sizeof(rr->srv.priority), state);
1262 siphash24_compress(&rr->srv.weight, sizeof(rr->srv.weight), state);
1263 siphash24_compress(&rr->srv.port, sizeof(rr->srv.port), state);
1264 dns_name_hash_func(rr->srv.name, state);
1265 break;
1266
1267 case DNS_TYPE_PTR:
1268 case DNS_TYPE_NS:
1269 case DNS_TYPE_CNAME:
1270 case DNS_TYPE_DNAME:
1271 dns_name_hash_func(rr->ptr.name, state);
1272 break;
1273
1274 case DNS_TYPE_HINFO:
1275 string_hash_func(rr->hinfo.cpu, state);
1276 string_hash_func(rr->hinfo.os, state);
1277 break;
1278
1279 case DNS_TYPE_TXT:
1280 case DNS_TYPE_SPF: {
1281 DnsTxtItem *j;
1282
1283 LIST_FOREACH(items, j, rr->txt.items) {
1284 siphash24_compress(j->data, j->length, state);
1285
d5115566
LP
1286 /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab"
1287 * followed by "". */
1288 siphash24_compress_byte(0, state);
c9c72065
LP
1289 }
1290 break;
1291 }
1292
1293 case DNS_TYPE_A:
1294 siphash24_compress(&rr->a.in_addr, sizeof(rr->a.in_addr), state);
1295 break;
1296
1297 case DNS_TYPE_AAAA:
1298 siphash24_compress(&rr->aaaa.in6_addr, sizeof(rr->aaaa.in6_addr), state);
1299 break;
1300
1301 case DNS_TYPE_SOA:
1302 dns_name_hash_func(rr->soa.mname, state);
1303 dns_name_hash_func(rr->soa.rname, state);
1304 siphash24_compress(&rr->soa.serial, sizeof(rr->soa.serial), state);
1305 siphash24_compress(&rr->soa.refresh, sizeof(rr->soa.refresh), state);
1306 siphash24_compress(&rr->soa.retry, sizeof(rr->soa.retry), state);
1307 siphash24_compress(&rr->soa.expire, sizeof(rr->soa.expire), state);
1308 siphash24_compress(&rr->soa.minimum, sizeof(rr->soa.minimum), state);
1309 break;
1310
1311 case DNS_TYPE_MX:
1312 siphash24_compress(&rr->mx.priority, sizeof(rr->mx.priority), state);
1313 dns_name_hash_func(rr->mx.exchange, state);
1314 break;
1315
1316 case DNS_TYPE_LOC:
1317 siphash24_compress(&rr->loc.version, sizeof(rr->loc.version), state);
1318 siphash24_compress(&rr->loc.size, sizeof(rr->loc.size), state);
1319 siphash24_compress(&rr->loc.horiz_pre, sizeof(rr->loc.horiz_pre), state);
1320 siphash24_compress(&rr->loc.vert_pre, sizeof(rr->loc.vert_pre), state);
1321 siphash24_compress(&rr->loc.latitude, sizeof(rr->loc.latitude), state);
1322 siphash24_compress(&rr->loc.longitude, sizeof(rr->loc.longitude), state);
1323 siphash24_compress(&rr->loc.altitude, sizeof(rr->loc.altitude), state);
1324 break;
1325
1326 case DNS_TYPE_SSHFP:
1327 siphash24_compress(&rr->sshfp.algorithm, sizeof(rr->sshfp.algorithm), state);
1328 siphash24_compress(&rr->sshfp.fptype, sizeof(rr->sshfp.fptype), state);
1329 siphash24_compress(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, state);
1330 break;
1331
1332 case DNS_TYPE_DNSKEY:
1333 siphash24_compress(&rr->dnskey.flags, sizeof(rr->dnskey.flags), state);
1334 siphash24_compress(&rr->dnskey.protocol, sizeof(rr->dnskey.protocol), state);
1335 siphash24_compress(&rr->dnskey.algorithm, sizeof(rr->dnskey.algorithm), state);
1336 siphash24_compress(rr->dnskey.key, rr->dnskey.key_size, state);
1337 break;
1338
1339 case DNS_TYPE_RRSIG:
1340 siphash24_compress(&rr->rrsig.type_covered, sizeof(rr->rrsig.type_covered), state);
1341 siphash24_compress(&rr->rrsig.algorithm, sizeof(rr->rrsig.algorithm), state);
1342 siphash24_compress(&rr->rrsig.labels, sizeof(rr->rrsig.labels), state);
1343 siphash24_compress(&rr->rrsig.original_ttl, sizeof(rr->rrsig.original_ttl), state);
1344 siphash24_compress(&rr->rrsig.expiration, sizeof(rr->rrsig.expiration), state);
1345 siphash24_compress(&rr->rrsig.inception, sizeof(rr->rrsig.inception), state);
1346 siphash24_compress(&rr->rrsig.key_tag, sizeof(rr->rrsig.key_tag), state);
1347 dns_name_hash_func(rr->rrsig.signer, state);
1348 siphash24_compress(rr->rrsig.signature, rr->rrsig.signature_size, state);
1349 break;
1350
1351 case DNS_TYPE_NSEC:
1352 dns_name_hash_func(rr->nsec.next_domain_name, state);
1353 /* FIXME: we leave out the type bitmap here. Hash
1354 * would be better if we'd take it into account
1355 * too. */
1356 break;
1357
1358 case DNS_TYPE_DS:
1359 siphash24_compress(&rr->ds.key_tag, sizeof(rr->ds.key_tag), state);
1360 siphash24_compress(&rr->ds.algorithm, sizeof(rr->ds.algorithm), state);
1361 siphash24_compress(&rr->ds.digest_type, sizeof(rr->ds.digest_type), state);
1362 siphash24_compress(rr->ds.digest, rr->ds.digest_size, state);
1363 break;
1364
1365 case DNS_TYPE_NSEC3:
1366 siphash24_compress(&rr->nsec3.algorithm, sizeof(rr->nsec3.algorithm), state);
1367 siphash24_compress(&rr->nsec3.flags, sizeof(rr->nsec3.flags), state);
1368 siphash24_compress(&rr->nsec3.iterations, sizeof(rr->nsec3.iterations), state);
1369 siphash24_compress(rr->nsec3.salt, rr->nsec3.salt_size, state);
1370 siphash24_compress(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, state);
1371 /* FIXME: We leave the bitmaps out */
1372 break;
48d45d2b
ZJS
1373
1374 case DNS_TYPE_TLSA:
1375 siphash24_compress(&rr->tlsa.cert_usage, sizeof(rr->tlsa.cert_usage), state);
1376 siphash24_compress(&rr->tlsa.selector, sizeof(rr->tlsa.selector), state);
1377 siphash24_compress(&rr->tlsa.matching_type, sizeof(rr->tlsa.matching_type), state);
1378 siphash24_compress(&rr->tlsa.data, rr->tlsa.data_size, state);
1379 break;
c9c72065
LP
1380
1381 default:
1382 siphash24_compress(rr->generic.data, rr->generic.size, state);
1383 break;
1384 }
1385}
1386
1387static int dns_resource_record_compare_func(const void *a, const void *b) {
1388 const DnsResourceRecord *x = a, *y = b;
1389 int ret;
1390
1391 ret = dns_resource_key_compare_func(x->key, y->key);
1392 if (ret != 0)
1393 return ret;
1394
1395 if (dns_resource_record_equal(x, y))
1396 return 0;
1397
1398 /* This is a bit dirty, we don't implement proper odering, but
1399 * the hashtable doesn't need ordering anyway, hence we don't
1400 * care. */
1401 return x < y ? -1 : 1;
1402}
1403
1404const struct hash_ops dns_resource_record_hash_ops = {
1405 .hash = dns_resource_record_hash_func,
1406 .compare = dns_resource_record_compare_func,
1407};
1408
2001c805
LP
1409DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
1410 DnsTxtItem *n;
1411
1412 if (!i)
1413 return NULL;
1414
1415 n = i->items_next;
1416
1417 free(i);
1418 return dns_txt_item_free_all(n);
1419}
1420
1421bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
1422
4d247a6c
LP
1423 if (a == b)
1424 return true;
1425
2001c805
LP
1426 if (!a != !b)
1427 return false;
1428
1429 if (!a)
1430 return true;
1431
1432 if (a->length != b->length)
1433 return false;
1434
1435 if (memcmp(a->data, b->data, a->length) != 0)
1436 return false;
1437
1438 return dns_txt_item_equal(a->items_next, b->items_next);
1439}
8730bccf
LP
1440
1441static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
6f717d08 1442 /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
8730bccf
LP
1443 [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
1444 [DNSSEC_ALGORITHM_DH] = "DH",
1445 [DNSSEC_ALGORITHM_DSA] = "DSA",
1446 [DNSSEC_ALGORITHM_ECC] = "ECC",
1447 [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
1448 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1",
1449 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1",
1450 [DNSSEC_ALGORITHM_RSASHA256] = "RSASHA256",
1451 [DNSSEC_ALGORITHM_RSASHA512] = "RSASHA512",
6f717d08
LP
1452 [DNSSEC_ALGORITHM_ECC_GOST] = "ECC-GOST",
1453 [DNSSEC_ALGORITHM_ECDSAP256SHA256] = "ECDSAP256SHA256",
1454 [DNSSEC_ALGORITHM_ECDSAP384SHA384] = "ECDSAP384SHA384",
8730bccf
LP
1455 [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
1456 [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
1457 [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
1458};
8e54f5d9 1459DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm, int, 255);
8730bccf
LP
1460
1461static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = {
6f717d08
LP
1462 /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
1463 [DNSSEC_DIGEST_SHA1] = "SHA-1",
1464 [DNSSEC_DIGEST_SHA256] = "SHA-256",
1465 [DNSSEC_DIGEST_GOST_R_34_11_94] = "GOST_R_34.11-94",
1466 [DNSSEC_DIGEST_SHA384] = "SHA-384",
8730bccf 1467};
8e54f5d9 1468DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest, int, 255);