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