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