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