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