resolved: do not use NSEC RRs from the wrong zone for proofs
[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;
faa133f3 347
74b2466e
LP
348 return rr;
349}
350
8bf52d3d
LP
351DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
352 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
353
354 key = dns_resource_key_new(class, type, name);
355 if (!key)
356 return NULL;
357
358 return dns_resource_record_new(key);
359}
360
74b2466e
LP
361DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
362 if (!rr)
363 return NULL;
364
365 assert(rr->n_ref > 0);
366 rr->n_ref++;
367
368 return rr;
369}
370
371DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
372 if (!rr)
373 return NULL;
374
375 assert(rr->n_ref > 0);
376
377 if (rr->n_ref > 1) {
378 rr->n_ref--;
379 return NULL;
380 }
381
faa133f3 382 if (rr->key) {
9de3e329 383 switch(rr->key->type) {
9c92ce6d
LP
384
385 case DNS_TYPE_SRV:
386 free(rr->srv.name);
387 break;
388
9de3e329
ZJS
389 case DNS_TYPE_PTR:
390 case DNS_TYPE_NS:
391 case DNS_TYPE_CNAME:
8ac4e9e1 392 case DNS_TYPE_DNAME:
faa133f3 393 free(rr->ptr.name);
9de3e329 394 break;
9c92ce6d 395
9de3e329 396 case DNS_TYPE_HINFO:
faa133f3
LP
397 free(rr->hinfo.cpu);
398 free(rr->hinfo.os);
9de3e329 399 break;
9c92ce6d 400
9de3e329 401 case DNS_TYPE_TXT:
9c92ce6d 402 case DNS_TYPE_SPF:
2001c805 403 dns_txt_item_free_all(rr->txt.items);
9de3e329 404 break;
9c92ce6d 405
9de3e329 406 case DNS_TYPE_SOA:
7e8e0422
LP
407 free(rr->soa.mname);
408 free(rr->soa.rname);
9de3e329 409 break;
9c92ce6d 410
9de3e329 411 case DNS_TYPE_MX:
946c7094 412 free(rr->mx.exchange);
9de3e329 413 break;
9c92ce6d 414
abf126a3
TG
415 case DNS_TYPE_DS:
416 free(rr->ds.digest);
417 break;
418
42cc2eeb 419 case DNS_TYPE_SSHFP:
549c1a25 420 free(rr->sshfp.fingerprint);
42cc2eeb
LP
421 break;
422
8db0d2f5
ZJS
423 case DNS_TYPE_DNSKEY:
424 free(rr->dnskey.key);
425 break;
426
151226ab
ZJS
427 case DNS_TYPE_RRSIG:
428 free(rr->rrsig.signer);
429 free(rr->rrsig.signature);
430 break;
431
50f1e641
TG
432 case DNS_TYPE_NSEC:
433 free(rr->nsec.next_domain_name);
434 bitmap_free(rr->nsec.types);
435 break;
436
5d45a880
TG
437 case DNS_TYPE_NSEC3:
438 free(rr->nsec3.next_hashed_name);
439 free(rr->nsec3.salt);
440 bitmap_free(rr->nsec3.types);
441 break;
442
0dae31d4 443 case DNS_TYPE_LOC:
9de3e329
ZJS
444 case DNS_TYPE_A:
445 case DNS_TYPE_AAAA:
446 break;
9c92ce6d 447
9de3e329 448 default:
faa133f3 449 free(rr->generic.data);
9de3e329 450 }
322345fd 451
a8812dd7 452 free(rr->wire_format);
faa133f3
LP
453 dns_resource_key_unref(rr->key);
454 }
322345fd 455
7b50eb2e 456 free(rr->to_string);
faa133f3 457 free(rr);
322345fd 458
322345fd
LP
459 return NULL;
460}
461
623a4c97
LP
462int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
463 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
464 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
465 _cleanup_free_ char *ptr = NULL;
466 int r;
467
468 assert(ret);
469 assert(address);
470 assert(hostname);
471
472 r = dns_name_reverse(family, address, &ptr);
473 if (r < 0)
474 return r;
475
476 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
477 if (!key)
478 return -ENOMEM;
479
480 ptr = NULL;
481
482 rr = dns_resource_record_new(key);
483 if (!rr)
484 return -ENOMEM;
485
486 rr->ptr.name = strdup(hostname);
487 if (!rr->ptr.name)
488 return -ENOMEM;
489
490 *ret = rr;
491 rr = NULL;
492
493 return 0;
494}
495
78c6a153
LP
496int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
497 DnsResourceRecord *rr;
498
499 assert(ret);
500 assert(address);
501 assert(family);
502
503 if (family == AF_INET) {
504
505 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
506 if (!rr)
507 return -ENOMEM;
508
509 rr->a.in_addr = address->in;
510
511 } else if (family == AF_INET6) {
512
513 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
514 if (!rr)
515 return -ENOMEM;
516
517 rr->aaaa.in6_addr = address->in6;
518 } else
519 return -EAFNOSUPPORT;
520
521 *ret = rr;
522
523 return 0;
524}
525
322345fd
LP
526int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
527 int r;
528
529 assert(a);
530 assert(b);
531
4d247a6c
LP
532 if (a == b)
533 return 1;
534
faa133f3 535 r = dns_resource_key_equal(a->key, b->key);
322345fd
LP
536 if (r <= 0)
537 return r;
538
fd0b4602
LP
539 if (a->unparseable != b->unparseable)
540 return 0;
541
542 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
2d4c5cbc 543
9c92ce6d
LP
544 case DNS_TYPE_SRV:
545 r = dns_name_equal(a->srv.name, b->srv.name);
546 if (r <= 0)
547 return r;
548
549 return a->srv.priority == b->srv.priority &&
550 a->srv.weight == b->srv.weight &&
551 a->srv.port == b->srv.port;
552
2d4c5cbc
LP
553 case DNS_TYPE_PTR:
554 case DNS_TYPE_NS:
555 case DNS_TYPE_CNAME:
8ac4e9e1 556 case DNS_TYPE_DNAME:
322345fd 557 return dns_name_equal(a->ptr.name, b->ptr.name);
2d4c5cbc
LP
558
559 case DNS_TYPE_HINFO:
560 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
561 strcaseeq(a->hinfo.os, b->hinfo.os);
562
9de3e329 563 case DNS_TYPE_SPF: /* exactly the same as TXT */
0f84a72e 564 case DNS_TYPE_TXT:
2001c805 565 return dns_txt_item_equal(a->txt.items, b->txt.items);
2e276efc 566
2d4c5cbc 567 case DNS_TYPE_A:
322345fd 568 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
2d4c5cbc
LP
569
570 case DNS_TYPE_AAAA:
322345fd 571 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
2d4c5cbc
LP
572
573 case DNS_TYPE_SOA:
7e8e0422
LP
574 r = dns_name_equal(a->soa.mname, b->soa.mname);
575 if (r <= 0)
576 return r;
577 r = dns_name_equal(a->soa.rname, b->soa.rname);
578 if (r <= 0)
579 return r;
580
581 return a->soa.serial == b->soa.serial &&
582 a->soa.refresh == b->soa.refresh &&
583 a->soa.retry == b->soa.retry &&
584 a->soa.expire == b->soa.expire &&
585 a->soa.minimum == b->soa.minimum;
9c92ce6d 586
946c7094
ZJS
587 case DNS_TYPE_MX:
588 if (a->mx.priority != b->mx.priority)
589 return 0;
590
591 return dns_name_equal(a->mx.exchange, b->mx.exchange);
592
0dae31d4
ZJS
593 case DNS_TYPE_LOC:
594 assert(a->loc.version == b->loc.version);
595
596 return a->loc.size == b->loc.size &&
597 a->loc.horiz_pre == b->loc.horiz_pre &&
598 a->loc.vert_pre == b->loc.vert_pre &&
599 a->loc.latitude == b->loc.latitude &&
600 a->loc.longitude == b->loc.longitude &&
601 a->loc.altitude == b->loc.altitude;
602
abf126a3
TG
603 case DNS_TYPE_DS:
604 return a->ds.key_tag == b->ds.key_tag &&
605 a->ds.algorithm == b->ds.algorithm &&
606 a->ds.digest_type == b->ds.digest_type &&
607 a->ds.digest_size == b->ds.digest_size &&
608 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
609
42cc2eeb
LP
610 case DNS_TYPE_SSHFP:
611 return a->sshfp.algorithm == b->sshfp.algorithm &&
612 a->sshfp.fptype == b->sshfp.fptype &&
549c1a25
TG
613 a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
614 memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
42cc2eeb 615
8db0d2f5 616 case DNS_TYPE_DNSKEY:
f91dc240
LP
617 return a->dnskey.flags == b->dnskey.flags &&
618 a->dnskey.protocol == b->dnskey.protocol &&
8db0d2f5
ZJS
619 a->dnskey.algorithm == b->dnskey.algorithm &&
620 a->dnskey.key_size == b->dnskey.key_size &&
621 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
622
151226ab
ZJS
623 case DNS_TYPE_RRSIG:
624 /* do the fast comparisons first */
03664a62
LN
625 if (a->rrsig.type_covered != b->rrsig.type_covered ||
626 a->rrsig.algorithm != b->rrsig.algorithm ||
627 a->rrsig.labels != b->rrsig.labels ||
628 a->rrsig.original_ttl != b->rrsig.original_ttl ||
629 a->rrsig.expiration != b->rrsig.expiration ||
630 a->rrsig.inception != b->rrsig.inception ||
631 a->rrsig.key_tag != b->rrsig.key_tag ||
151226ab
ZJS
632 a->rrsig.signature_size != b->rrsig.signature_size ||
633 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
634 return false;
635
636 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
637
50f1e641
TG
638 case DNS_TYPE_NSEC:
639 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
640 bitmap_equal(a->nsec.types, b->nsec.types);
641
5d45a880
TG
642 case DNS_TYPE_NSEC3:
643 return a->nsec3.algorithm == b->nsec3.algorithm &&
644 a->nsec3.flags == b->nsec3.flags &&
645 a->nsec3.iterations == b->nsec3.iterations &&
646 a->nsec3.salt_size == b->nsec3.salt_size &&
647 memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
648 memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
649 bitmap_equal(a->nsec3.types, b->nsec3.types);
650
2d4c5cbc 651 default:
322345fd
LP
652 return a->generic.size == b->generic.size &&
653 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
2d4c5cbc 654 }
322345fd
LP
655}
656
0dae31d4
ZJS
657static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
658 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
659 char *s;
660 char NS = latitude >= 1U<<31 ? 'N' : 'S';
661 char EW = longitude >= 1U<<31 ? 'E' : 'W';
662
663 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
664 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
665 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
666 double siz = (size >> 4) * exp10((double) (size & 0xF));
667 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
668 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
669
670 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
671 (lat / 60000 / 60),
672 (lat / 60000) % 60,
673 (lat % 60000) / 1000.,
674 NS,
675 (lon / 60000 / 60),
676 (lon / 60000) % 60,
677 (lon % 60000) / 1000.,
678 EW,
679 alt / 100.,
680 siz / 100.,
681 hor / 100.,
682 ver / 100.) < 0)
683 return NULL;
684
685 return s;
686}
687
7c6423e1
TG
688static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
689 struct tm tm;
690
691 assert(buf);
692 assert(l > strlen("YYYYMMDDHHmmSS"));
693
694 if (!gmtime_r(&sec, &tm))
695 return -EINVAL;
696
697 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
698 return -EINVAL;
699
700 return 0;
701}
702
50f1e641
TG
703static char *format_types(Bitmap *types) {
704 _cleanup_strv_free_ char **strv = NULL;
705 _cleanup_free_ char *str = NULL;
cb57dd41 706 Iterator i;
50f1e641
TG
707 unsigned type;
708 int r;
709
cb57dd41 710 BITMAP_FOREACH(type, types, i) {
50f1e641 711 if (dns_type_to_string(type)) {
2c1fb4f7 712 r = strv_extend(&strv, dns_type_to_string(type));
50f1e641
TG
713 if (r < 0)
714 return NULL;
715 } else {
716 char *t;
717
718 r = asprintf(&t, "TYPE%u", type);
719 if (r < 0)
720 return NULL;
721
2c1fb4f7 722 r = strv_consume(&strv, t);
50f1e641
TG
723 if (r < 0)
724 return NULL;
725 }
726 }
727
728 str = strv_join(strv, " ");
729 if (!str)
730 return NULL;
731
732 return strjoin("( ", str, " )", NULL);
733}
734
2001c805
LP
735static char *format_txt(DnsTxtItem *first) {
736 DnsTxtItem *i;
737 size_t c = 1;
738 char *p, *s;
739
740 LIST_FOREACH(items, i, first)
741 c += i->length * 4 + 3;
742
743 p = s = new(char, c);
744 if (!s)
745 return NULL;
746
747 LIST_FOREACH(items, i, first) {
748 size_t j;
749
750 if (i != first)
751 *(p++) = ' ';
752
753 *(p++) = '"';
754
755 for (j = 0; j < i->length; j++) {
756 if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) {
757 *(p++) = '\\';
758 *(p++) = '0' + (i->data[j] / 100);
759 *(p++) = '0' + ((i->data[j] / 10) % 10);
760 *(p++) = '0' + (i->data[j] % 10);
761 } else
762 *(p++) = i->data[j];
763 }
764
765 *(p++) = '"';
766 }
767
768 *p = 0;
769 return s;
770}
771
7b50eb2e 772const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
8db0d2f5 773 _cleanup_free_ char *k = NULL, *t = NULL;
2d4c5cbc
LP
774 char *s;
775 int r;
322345fd 776
2d4c5cbc 777 assert(rr);
322345fd 778
7b50eb2e
LP
779 if (rr->to_string)
780 return rr->to_string;
781
2d4c5cbc
LP
782 r = dns_resource_key_to_string(rr->key, &k);
783 if (r < 0)
7b50eb2e 784 return NULL;
322345fd 785
0dae31d4 786 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
322345fd 787
9c92ce6d
LP
788 case DNS_TYPE_SRV:
789 r = asprintf(&s, "%s %u %u %u %s",
790 k,
791 rr->srv.priority,
792 rr->srv.weight,
793 rr->srv.port,
794 strna(rr->srv.name));
795 if (r < 0)
7b50eb2e 796 return NULL;
9c92ce6d
LP
797 break;
798
2d4c5cbc
LP
799 case DNS_TYPE_PTR:
800 case DNS_TYPE_NS:
801 case DNS_TYPE_CNAME:
8ac4e9e1 802 case DNS_TYPE_DNAME:
2d4c5cbc
LP
803 s = strjoin(k, " ", rr->ptr.name, NULL);
804 if (!s)
7b50eb2e 805 return NULL;
322345fd 806
2d4c5cbc 807 break;
322345fd 808
2d4c5cbc
LP
809 case DNS_TYPE_HINFO:
810 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
811 if (!s)
7b50eb2e 812 return NULL;
2d4c5cbc 813 break;
322345fd 814
9de3e329 815 case DNS_TYPE_SPF: /* exactly the same as TXT */
8db0d2f5 816 case DNS_TYPE_TXT:
2001c805 817 t = format_txt(rr->txt.items);
2e276efc 818 if (!t)
7b50eb2e 819 return NULL;
2e276efc
ZJS
820
821 s = strjoin(k, " ", t, NULL);
822 if (!s)
7b50eb2e 823 return NULL;
2e276efc 824 break;
2e276efc 825
2d4c5cbc
LP
826 case DNS_TYPE_A: {
827 _cleanup_free_ char *x = NULL;
322345fd 828
2d4c5cbc
LP
829 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
830 if (r < 0)
7b50eb2e 831 return NULL;
322345fd 832
2d4c5cbc
LP
833 s = strjoin(k, " ", x, NULL);
834 if (!s)
7b50eb2e 835 return NULL;
2d4c5cbc
LP
836 break;
837 }
322345fd 838
8db0d2f5
ZJS
839 case DNS_TYPE_AAAA:
840 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
2d4c5cbc 841 if (r < 0)
7b50eb2e 842 return NULL;
322345fd 843
8db0d2f5 844 s = strjoin(k, " ", t, NULL);
2d4c5cbc 845 if (!s)
7b50eb2e 846 return NULL;
2d4c5cbc 847 break;
322345fd 848
2d4c5cbc
LP
849 case DNS_TYPE_SOA:
850 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
851 k,
852 strna(rr->soa.mname),
853 strna(rr->soa.rname),
854 rr->soa.serial,
855 rr->soa.refresh,
856 rr->soa.retry,
857 rr->soa.expire,
858 rr->soa.minimum);
859 if (r < 0)
7b50eb2e 860 return NULL;
2d4c5cbc
LP
861 break;
862
946c7094
ZJS
863 case DNS_TYPE_MX:
864 r = asprintf(&s, "%s %u %s",
865 k,
866 rr->mx.priority,
867 rr->mx.exchange);
868 if (r < 0)
7b50eb2e 869 return NULL;
946c7094
ZJS
870 break;
871
8db0d2f5 872 case DNS_TYPE_LOC:
0dae31d4
ZJS
873 assert(rr->loc.version == 0);
874
8db0d2f5
ZJS
875 t = format_location(rr->loc.latitude,
876 rr->loc.longitude,
877 rr->loc.altitude,
878 rr->loc.size,
879 rr->loc.horiz_pre,
880 rr->loc.vert_pre);
881 if (!t)
7b50eb2e 882 return NULL;
0dae31d4 883
8db0d2f5 884 s = strjoin(k, " ", t, NULL);
0dae31d4 885 if (!s)
7b50eb2e 886 return NULL;
0dae31d4 887 break;
0dae31d4 888
abf126a3
TG
889 case DNS_TYPE_DS:
890 t = hexmem(rr->ds.digest, rr->ds.digest_size);
891 if (!t)
7b50eb2e 892 return NULL;
abf126a3
TG
893
894 r = asprintf(&s, "%s %u %u %u %s",
895 k,
896 rr->ds.key_tag,
897 rr->ds.algorithm,
898 rr->ds.digest_type,
899 t);
900 if (r < 0)
7b50eb2e 901 return NULL;
abf126a3
TG
902 break;
903
8db0d2f5 904 case DNS_TYPE_SSHFP:
549c1a25 905 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
8db0d2f5 906 if (!t)
7b50eb2e 907 return NULL;
42cc2eeb
LP
908
909 r = asprintf(&s, "%s %u %u %s",
910 k,
911 rr->sshfp.algorithm,
912 rr->sshfp.fptype,
8db0d2f5 913 t);
42cc2eeb 914 if (r < 0)
7b50eb2e 915 return NULL;
42cc2eeb 916 break;
42cc2eeb 917
ff3d6560 918 case DNS_TYPE_DNSKEY: {
8e54f5d9 919 _cleanup_free_ char *alg = NULL;
ff3d6560 920
8e54f5d9
LP
921 r = dnssec_algorithm_to_string_alloc(rr->dnskey.algorithm, &alg);
922 if (r < 0)
923 return NULL;
ff3d6560 924
1bf968f3 925 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
8db0d2f5 926 if (!t)
7b50eb2e 927 return NULL;
2d4c5cbc 928
8e54f5d9 929 r = asprintf(&s, "%s %u %u %s %s",
8db0d2f5 930 k,
f91dc240
LP
931 rr->dnskey.flags,
932 rr->dnskey.protocol,
8e54f5d9 933 alg,
8db0d2f5
ZJS
934 t);
935 if (r < 0)
7b50eb2e 936 return NULL;
8db0d2f5 937 break;
ff3d6560 938 }
2d4c5cbc 939
151226ab 940 case DNS_TYPE_RRSIG: {
8e54f5d9 941 _cleanup_free_ char *alg = NULL;
7c6423e1 942 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
8e54f5d9 943 const char *type;
151226ab
ZJS
944
945 type = dns_type_to_string(rr->rrsig.type_covered);
8e54f5d9
LP
946
947 r = dnssec_algorithm_to_string_alloc(rr->rrsig.algorithm, &alg);
948 if (r < 0)
949 return NULL;
151226ab 950
1bf968f3 951 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
151226ab 952 if (!t)
7b50eb2e 953 return NULL;
151226ab 954
7c6423e1
TG
955 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
956 if (r < 0)
7b50eb2e 957 return NULL;
7c6423e1
TG
958
959 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
960 if (r < 0)
7b50eb2e 961 return NULL;
7c6423e1 962
151226ab
ZJS
963 /* TYPE?? follows
964 * http://tools.ietf.org/html/rfc3597#section-5 */
965
8e54f5d9 966 r = asprintf(&s, "%s %s%.*u %s %u %u %s %s %u %s %s",
151226ab
ZJS
967 k,
968 type ?: "TYPE",
969 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
8e54f5d9 970 alg,
151226ab
ZJS
971 rr->rrsig.labels,
972 rr->rrsig.original_ttl,
7c6423e1
TG
973 expiration,
974 inception,
151226ab
ZJS
975 rr->rrsig.key_tag,
976 rr->rrsig.signer,
977 t);
978 if (r < 0)
7b50eb2e 979 return NULL;
151226ab
ZJS
980 break;
981 }
982
50f1e641
TG
983 case DNS_TYPE_NSEC:
984 t = format_types(rr->nsec.types);
985 if (!t)
7b50eb2e 986 return NULL;
50f1e641
TG
987
988 r = asprintf(&s, "%s %s %s",
989 k,
990 rr->nsec.next_domain_name,
991 t);
992 if (r < 0)
7b50eb2e 993 return NULL;
50f1e641
TG
994 break;
995
5d45a880
TG
996 case DNS_TYPE_NSEC3: {
997 _cleanup_free_ char *salt = NULL, *hash = NULL;
998
f5430a3e 999 if (rr->nsec3.salt_size > 0) {
5d45a880
TG
1000 salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
1001 if (!salt)
7b50eb2e 1002 return NULL;
5d45a880
TG
1003 }
1004
1005 hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
1006 if (!hash)
7b50eb2e 1007 return NULL;
5d45a880
TG
1008
1009 t = format_types(rr->nsec3.types);
1010 if (!t)
7b50eb2e 1011 return NULL;
5d45a880
TG
1012
1013 r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
1014 k,
1015 rr->nsec3.algorithm,
1016 rr->nsec3.flags,
1017 rr->nsec3.iterations,
f5430a3e 1018 rr->nsec3.salt_size > 0 ? salt : "-",
5d45a880
TG
1019 hash,
1020 t);
1021 if (r < 0)
7b50eb2e 1022 return NULL;
5d45a880
TG
1023
1024 break;
1025 }
1026
8db0d2f5
ZJS
1027 default:
1028 t = hexmem(rr->generic.data, rr->generic.size);
1029 if (!t)
7b50eb2e 1030 return NULL;
8db0d2f5 1031
6af47493 1032 /* Format as documented in RFC 3597, Section 5 */
f5430a3e 1033 r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
d23a27a9 1034 if (r < 0)
7b50eb2e 1035 return NULL;
2d4c5cbc 1036 break;
8db0d2f5 1037 }
2d4c5cbc 1038
7b50eb2e
LP
1039 rr->to_string = s;
1040 return s;
2d4c5cbc 1041}
322345fd 1042
a8812dd7
LP
1043int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {
1044
1045 DnsPacket packet = {
1046 .n_ref = 1,
1047 .protocol = DNS_PROTOCOL_DNS,
1048 .on_stack = true,
1049 .refuse_compression = true,
1050 .canonical_form = canonical,
1051 };
1052
1053 size_t start, rds;
1054 int r;
1055
1056 assert(rr);
1057
1058 /* Generates the RR in wire-format, optionally in the
1059 * canonical form as discussed in the DNSSEC RFC 4034, Section
1060 * 6.2. We allocate a throw-away DnsPacket object on the stack
1061 * here, because we need some book-keeping for memory
1062 * management, and can reuse the DnsPacket serializer, that
1063 * can generate the canonical form, too, but also knows label
1064 * compression and suchlike. */
1065
1066 if (rr->wire_format && rr->wire_format_canonical == canonical)
1067 return 0;
1068
1069 r = dns_packet_append_rr(&packet, rr, &start, &rds);
1070 if (r < 0)
1071 return r;
1072
1073 assert(start == 0);
1074 assert(packet._data);
1075
1076 free(rr->wire_format);
1077 rr->wire_format = packet._data;
1078 rr->wire_format_size = packet.size;
1079 rr->wire_format_rdata_offset = rds;
1080 rr->wire_format_canonical = canonical;
1081
1082 packet._data = NULL;
1083 dns_packet_unref(&packet);
1084
1085 return 0;
1086}
1087
c9c72065
LP
1088static void dns_resource_record_hash_func(const void *i, struct siphash *state) {
1089 const DnsResourceRecord *rr = i;
1090
1091 assert(rr);
1092
1093 dns_resource_key_hash_func(rr->key, state);
1094
1095 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
1096
1097 case DNS_TYPE_SRV:
1098 siphash24_compress(&rr->srv.priority, sizeof(rr->srv.priority), state);
1099 siphash24_compress(&rr->srv.weight, sizeof(rr->srv.weight), state);
1100 siphash24_compress(&rr->srv.port, sizeof(rr->srv.port), state);
1101 dns_name_hash_func(rr->srv.name, state);
1102 break;
1103
1104 case DNS_TYPE_PTR:
1105 case DNS_TYPE_NS:
1106 case DNS_TYPE_CNAME:
1107 case DNS_TYPE_DNAME:
1108 dns_name_hash_func(rr->ptr.name, state);
1109 break;
1110
1111 case DNS_TYPE_HINFO:
1112 string_hash_func(rr->hinfo.cpu, state);
1113 string_hash_func(rr->hinfo.os, state);
1114 break;
1115
1116 case DNS_TYPE_TXT:
1117 case DNS_TYPE_SPF: {
1118 DnsTxtItem *j;
1119
1120 LIST_FOREACH(items, j, rr->txt.items) {
1121 siphash24_compress(j->data, j->length, state);
1122
d5115566
LP
1123 /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab"
1124 * followed by "". */
1125 siphash24_compress_byte(0, state);
c9c72065
LP
1126 }
1127 break;
1128 }
1129
1130 case DNS_TYPE_A:
1131 siphash24_compress(&rr->a.in_addr, sizeof(rr->a.in_addr), state);
1132 break;
1133
1134 case DNS_TYPE_AAAA:
1135 siphash24_compress(&rr->aaaa.in6_addr, sizeof(rr->aaaa.in6_addr), state);
1136 break;
1137
1138 case DNS_TYPE_SOA:
1139 dns_name_hash_func(rr->soa.mname, state);
1140 dns_name_hash_func(rr->soa.rname, state);
1141 siphash24_compress(&rr->soa.serial, sizeof(rr->soa.serial), state);
1142 siphash24_compress(&rr->soa.refresh, sizeof(rr->soa.refresh), state);
1143 siphash24_compress(&rr->soa.retry, sizeof(rr->soa.retry), state);
1144 siphash24_compress(&rr->soa.expire, sizeof(rr->soa.expire), state);
1145 siphash24_compress(&rr->soa.minimum, sizeof(rr->soa.minimum), state);
1146 break;
1147
1148 case DNS_TYPE_MX:
1149 siphash24_compress(&rr->mx.priority, sizeof(rr->mx.priority), state);
1150 dns_name_hash_func(rr->mx.exchange, state);
1151 break;
1152
1153 case DNS_TYPE_LOC:
1154 siphash24_compress(&rr->loc.version, sizeof(rr->loc.version), state);
1155 siphash24_compress(&rr->loc.size, sizeof(rr->loc.size), state);
1156 siphash24_compress(&rr->loc.horiz_pre, sizeof(rr->loc.horiz_pre), state);
1157 siphash24_compress(&rr->loc.vert_pre, sizeof(rr->loc.vert_pre), state);
1158 siphash24_compress(&rr->loc.latitude, sizeof(rr->loc.latitude), state);
1159 siphash24_compress(&rr->loc.longitude, sizeof(rr->loc.longitude), state);
1160 siphash24_compress(&rr->loc.altitude, sizeof(rr->loc.altitude), state);
1161 break;
1162
1163 case DNS_TYPE_SSHFP:
1164 siphash24_compress(&rr->sshfp.algorithm, sizeof(rr->sshfp.algorithm), state);
1165 siphash24_compress(&rr->sshfp.fptype, sizeof(rr->sshfp.fptype), state);
1166 siphash24_compress(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, state);
1167 break;
1168
1169 case DNS_TYPE_DNSKEY:
1170 siphash24_compress(&rr->dnskey.flags, sizeof(rr->dnskey.flags), state);
1171 siphash24_compress(&rr->dnskey.protocol, sizeof(rr->dnskey.protocol), state);
1172 siphash24_compress(&rr->dnskey.algorithm, sizeof(rr->dnskey.algorithm), state);
1173 siphash24_compress(rr->dnskey.key, rr->dnskey.key_size, state);
1174 break;
1175
1176 case DNS_TYPE_RRSIG:
1177 siphash24_compress(&rr->rrsig.type_covered, sizeof(rr->rrsig.type_covered), state);
1178 siphash24_compress(&rr->rrsig.algorithm, sizeof(rr->rrsig.algorithm), state);
1179 siphash24_compress(&rr->rrsig.labels, sizeof(rr->rrsig.labels), state);
1180 siphash24_compress(&rr->rrsig.original_ttl, sizeof(rr->rrsig.original_ttl), state);
1181 siphash24_compress(&rr->rrsig.expiration, sizeof(rr->rrsig.expiration), state);
1182 siphash24_compress(&rr->rrsig.inception, sizeof(rr->rrsig.inception), state);
1183 siphash24_compress(&rr->rrsig.key_tag, sizeof(rr->rrsig.key_tag), state);
1184 dns_name_hash_func(rr->rrsig.signer, state);
1185 siphash24_compress(rr->rrsig.signature, rr->rrsig.signature_size, state);
1186 break;
1187
1188 case DNS_TYPE_NSEC:
1189 dns_name_hash_func(rr->nsec.next_domain_name, state);
1190 /* FIXME: we leave out the type bitmap here. Hash
1191 * would be better if we'd take it into account
1192 * too. */
1193 break;
1194
1195 case DNS_TYPE_DS:
1196 siphash24_compress(&rr->ds.key_tag, sizeof(rr->ds.key_tag), state);
1197 siphash24_compress(&rr->ds.algorithm, sizeof(rr->ds.algorithm), state);
1198 siphash24_compress(&rr->ds.digest_type, sizeof(rr->ds.digest_type), state);
1199 siphash24_compress(rr->ds.digest, rr->ds.digest_size, state);
1200 break;
1201
1202 case DNS_TYPE_NSEC3:
1203 siphash24_compress(&rr->nsec3.algorithm, sizeof(rr->nsec3.algorithm), state);
1204 siphash24_compress(&rr->nsec3.flags, sizeof(rr->nsec3.flags), state);
1205 siphash24_compress(&rr->nsec3.iterations, sizeof(rr->nsec3.iterations), state);
1206 siphash24_compress(rr->nsec3.salt, rr->nsec3.salt_size, state);
1207 siphash24_compress(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, state);
1208 /* FIXME: We leave the bitmaps out */
1209 break;
1210
1211 default:
1212 siphash24_compress(rr->generic.data, rr->generic.size, state);
1213 break;
1214 }
1215}
1216
1217static int dns_resource_record_compare_func(const void *a, const void *b) {
1218 const DnsResourceRecord *x = a, *y = b;
1219 int ret;
1220
1221 ret = dns_resource_key_compare_func(x->key, y->key);
1222 if (ret != 0)
1223 return ret;
1224
1225 if (dns_resource_record_equal(x, y))
1226 return 0;
1227
1228 /* This is a bit dirty, we don't implement proper odering, but
1229 * the hashtable doesn't need ordering anyway, hence we don't
1230 * care. */
1231 return x < y ? -1 : 1;
1232}
1233
1234const struct hash_ops dns_resource_record_hash_ops = {
1235 .hash = dns_resource_record_hash_func,
1236 .compare = dns_resource_record_compare_func,
1237};
1238
2001c805
LP
1239DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
1240 DnsTxtItem *n;
1241
1242 if (!i)
1243 return NULL;
1244
1245 n = i->items_next;
1246
1247 free(i);
1248 return dns_txt_item_free_all(n);
1249}
1250
1251bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
1252
4d247a6c
LP
1253 if (a == b)
1254 return true;
1255
2001c805
LP
1256 if (!a != !b)
1257 return false;
1258
1259 if (!a)
1260 return true;
1261
1262 if (a->length != b->length)
1263 return false;
1264
1265 if (memcmp(a->data, b->data, a->length) != 0)
1266 return false;
1267
1268 return dns_txt_item_equal(a->items_next, b->items_next);
1269}
8730bccf
LP
1270
1271static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
6f717d08 1272 /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
8730bccf
LP
1273 [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
1274 [DNSSEC_ALGORITHM_DH] = "DH",
1275 [DNSSEC_ALGORITHM_DSA] = "DSA",
1276 [DNSSEC_ALGORITHM_ECC] = "ECC",
1277 [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
1278 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1",
1279 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1",
1280 [DNSSEC_ALGORITHM_RSASHA256] = "RSASHA256",
1281 [DNSSEC_ALGORITHM_RSASHA512] = "RSASHA512",
6f717d08
LP
1282 [DNSSEC_ALGORITHM_ECC_GOST] = "ECC-GOST",
1283 [DNSSEC_ALGORITHM_ECDSAP256SHA256] = "ECDSAP256SHA256",
1284 [DNSSEC_ALGORITHM_ECDSAP384SHA384] = "ECDSAP384SHA384",
8730bccf
LP
1285 [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
1286 [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
1287 [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
1288};
8e54f5d9 1289DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm, int, 255);
8730bccf
LP
1290
1291static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = {
6f717d08
LP
1292 /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
1293 [DNSSEC_DIGEST_SHA1] = "SHA-1",
1294 [DNSSEC_DIGEST_SHA256] = "SHA-256",
1295 [DNSSEC_DIGEST_GOST_R_34_11_94] = "GOST_R_34.11-94",
1296 [DNSSEC_DIGEST_SHA384] = "SHA-384",
8730bccf 1297};
8e54f5d9 1298DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest, int, 255);