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