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