1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include "alloc-util.h"
24 #include "dns-domain.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"
34 #include "terminal-util.h"
36 DnsResourceKey
* dns_resource_key_new(uint16_t class, uint16_t type
, const char *name
) {
43 k
= malloc0(sizeof(DnsResourceKey
) + l
+ 1);
51 strcpy((char*) k
+ sizeof(DnsResourceKey
), name
);
56 DnsResourceKey
* dns_resource_key_new_redirect(const DnsResourceKey
*key
, const DnsResourceRecord
*cname
) {
62 assert(IN_SET(cname
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
));
64 if (cname
->key
->type
== DNS_TYPE_CNAME
)
65 return dns_resource_key_new(key
->class, key
->type
, cname
->cname
.name
);
68 char *destination
= NULL
;
70 r
= dns_name_change_suffix(dns_resource_key_name(key
), dns_resource_key_name(cname
->key
), cname
->dname
.name
, &destination
);
74 return dns_resource_key_ref((DnsResourceKey
*) key
);
76 k
= dns_resource_key_new_consume(key
->class, key
->type
, destination
);
78 return mfree(destination
);
84 int dns_resource_key_new_append_suffix(DnsResourceKey
**ret
, DnsResourceKey
*key
, char *name
) {
85 DnsResourceKey
*new_key
;
93 if (dns_name_is_root(name
)) {
94 *ret
= dns_resource_key_ref(key
);
98 r
= dns_name_concat(dns_resource_key_name(key
), name
, &joined
);
102 new_key
= dns_resource_key_new_consume(key
->class, key
->type
, joined
);
112 DnsResourceKey
* dns_resource_key_new_consume(uint16_t class, uint16_t type
, char *name
) {
117 k
= new0(DnsResourceKey
, 1);
129 DnsResourceKey
* dns_resource_key_ref(DnsResourceKey
*k
) {
134 /* Static/const keys created with DNS_RESOURCE_KEY_CONST will
135 * set this to -1, they should not be reffed/unreffed */
136 assert(k
->n_ref
!= (unsigned) -1);
138 assert(k
->n_ref
> 0);
144 DnsResourceKey
* dns_resource_key_unref(DnsResourceKey
*k
) {
148 assert(k
->n_ref
!= (unsigned) -1);
149 assert(k
->n_ref
> 0);
160 const char* dns_resource_key_name(const DnsResourceKey
*key
) {
169 name
= (char*) key
+ sizeof(DnsResourceKey
);
171 if (dns_name_is_root(name
))
177 bool dns_resource_key_is_address(const DnsResourceKey
*key
) {
180 /* Check if this is an A or AAAA resource key */
182 return key
->class == DNS_CLASS_IN
&& IN_SET(key
->type
, DNS_TYPE_A
, DNS_TYPE_AAAA
);
185 bool dns_resource_key_is_dnssd_ptr(const DnsResourceKey
*key
) {
188 /* Check if this is a PTR resource key used in
189 Service Instance Enumeration as described in RFC6763 p4.1. */
191 if (key
->type
!= DNS_TYPE_PTR
)
194 return dns_name_endswith(dns_resource_key_name(key
), "_tcp.local") ||
195 dns_name_endswith(dns_resource_key_name(key
), "_udp.local");
198 int dns_resource_key_equal(const DnsResourceKey
*a
, const DnsResourceKey
*b
) {
204 r
= dns_name_equal(dns_resource_key_name(a
), dns_resource_key_name(b
));
208 if (a
->class != b
->class)
211 if (a
->type
!= b
->type
)
217 int dns_resource_key_match_rr(const DnsResourceKey
*key
, DnsResourceRecord
*rr
, const char *search_domain
) {
226 /* Checks if an rr matches the specified key. If a search
227 * domain is specified, it will also be checked if the key
228 * with the search domain suffixed might match the RR. */
230 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
233 if (rr
->key
->type
!= key
->type
&& key
->type
!= DNS_TYPE_ANY
)
236 r
= dns_name_equal(dns_resource_key_name(rr
->key
), dns_resource_key_name(key
));
241 _cleanup_free_
char *joined
= NULL
;
243 r
= dns_name_concat(dns_resource_key_name(key
), search_domain
, &joined
);
247 return dns_name_equal(dns_resource_key_name(rr
->key
), joined
);
253 int dns_resource_key_match_cname_or_dname(const DnsResourceKey
*key
, const DnsResourceKey
*cname
, const char *search_domain
) {
259 if (cname
->class != key
->class && key
->class != DNS_CLASS_ANY
)
262 if (cname
->type
== DNS_TYPE_CNAME
)
263 r
= dns_name_equal(dns_resource_key_name(key
), dns_resource_key_name(cname
));
264 else if (cname
->type
== DNS_TYPE_DNAME
)
265 r
= dns_name_endswith(dns_resource_key_name(key
), dns_resource_key_name(cname
));
273 _cleanup_free_
char *joined
= NULL
;
275 r
= dns_name_concat(dns_resource_key_name(key
), search_domain
, &joined
);
279 if (cname
->type
== DNS_TYPE_CNAME
)
280 return dns_name_equal(joined
, dns_resource_key_name(cname
));
281 else if (cname
->type
== DNS_TYPE_DNAME
)
282 return dns_name_endswith(joined
, dns_resource_key_name(cname
));
288 int dns_resource_key_match_soa(const DnsResourceKey
*key
, const DnsResourceKey
*soa
) {
292 /* Checks whether 'soa' is a SOA record for the specified key. */
294 if (soa
->class != key
->class)
297 if (soa
->type
!= DNS_TYPE_SOA
)
300 return dns_name_endswith(dns_resource_key_name(key
), dns_resource_key_name(soa
));
303 static void dns_resource_key_hash_func(const void *i
, struct siphash
*state
) {
304 const DnsResourceKey
*k
= i
;
308 dns_name_hash_func(dns_resource_key_name(k
), state
);
309 siphash24_compress(&k
->class, sizeof(k
->class), state
);
310 siphash24_compress(&k
->type
, sizeof(k
->type
), state
);
313 static int dns_resource_key_compare_func(const void *a
, const void *b
) {
314 const DnsResourceKey
*x
= a
, *y
= b
;
317 ret
= dns_name_compare_func(dns_resource_key_name(x
), dns_resource_key_name(y
));
321 if (x
->type
< y
->type
)
323 if (x
->type
> y
->type
)
326 if (x
->class < y
->class)
328 if (x
->class > y
->class)
334 const struct hash_ops dns_resource_key_hash_ops
= {
335 .hash
= dns_resource_key_hash_func
,
336 .compare
= dns_resource_key_compare_func
339 char* dns_resource_key_to_string(const DnsResourceKey
*key
, char *buf
, size_t buf_size
) {
343 /* If we cannot convert the CLASS/TYPE into a known string,
344 use the format recommended by RFC 3597, Section 5. */
346 c
= dns_class_to_string(key
->class);
347 t
= dns_type_to_string(key
->type
);
349 snprintf(buf
, buf_size
, "%s %s%s%.0u %s%s%.0u",
350 dns_resource_key_name(key
),
351 strempty(c
), c
? "" : "CLASS", c
? 0 : key
->class,
352 strempty(t
), t
? "" : "TYPE", t
? 0 : key
->class);
357 bool dns_resource_key_reduce(DnsResourceKey
**a
, DnsResourceKey
**b
) {
361 /* Try to replace one RR key by another if they are identical, thus saving a bit of memory. Note that we do
362 * this only for RR keys, not for RRs themselves, as they carry a lot of additional metadata (where they come
363 * from, validity data, and suchlike), and cannot be replaced so easily by other RRs that have the same
364 * superficial data. */
371 /* We refuse merging const keys */
372 if ((*a
)->n_ref
== (unsigned) -1)
374 if ((*b
)->n_ref
== (unsigned) -1)
377 /* Already the same? */
381 /* Are they really identical? */
382 if (dns_resource_key_equal(*a
, *b
) <= 0)
385 /* Keep the one which already has more references. */
386 if ((*a
)->n_ref
> (*b
)->n_ref
) {
387 dns_resource_key_unref(*b
);
388 *b
= dns_resource_key_ref(*a
);
390 dns_resource_key_unref(*a
);
391 *a
= dns_resource_key_ref(*b
);
397 DnsResourceRecord
* dns_resource_record_new(DnsResourceKey
*key
) {
398 DnsResourceRecord
*rr
;
400 rr
= new0(DnsResourceRecord
, 1);
405 rr
->key
= dns_resource_key_ref(key
);
406 rr
->expiry
= USEC_INFINITY
;
407 rr
->n_skip_labels_signer
= rr
->n_skip_labels_source
= (unsigned) -1;
412 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
413 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
415 key
= dns_resource_key_new(class, type
, name
);
419 return dns_resource_record_new(key
);
422 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
426 assert(rr
->n_ref
> 0);
432 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
436 assert(rr
->n_ref
> 0);
444 switch(rr
->key
->type
) {
464 dns_txt_item_free_all(rr
->txt
.items
);
473 free(rr
->mx
.exchange
);
481 free(rr
->sshfp
.fingerprint
);
484 case DNS_TYPE_DNSKEY
:
485 free(rr
->dnskey
.key
);
489 free(rr
->rrsig
.signer
);
490 free(rr
->rrsig
.signature
);
494 free(rr
->nsec
.next_domain_name
);
495 bitmap_free(rr
->nsec
.types
);
499 free(rr
->nsec3
.next_hashed_name
);
500 free(rr
->nsec3
.salt
);
501 bitmap_free(rr
->nsec3
.types
);
518 case DNS_TYPE_OPENPGPKEY
:
520 free(rr
->generic
.data
);
523 free(rr
->wire_format
);
524 dns_resource_key_unref(rr
->key
);
531 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
532 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
533 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
534 _cleanup_free_
char *ptr
= NULL
;
541 r
= dns_name_reverse(family
, address
, &ptr
);
545 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
551 rr
= dns_resource_record_new(key
);
555 rr
->ptr
.name
= strdup(hostname
);
565 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
566 DnsResourceRecord
*rr
;
572 if (family
== AF_INET
) {
574 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
578 rr
->a
.in_addr
= address
->in
;
580 } else if (family
== AF_INET6
) {
582 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
586 rr
->aaaa
.in6_addr
= address
->in6
;
588 return -EAFNOSUPPORT
;
595 #define FIELD_EQUAL(a, b, field) \
596 ((a).field ## _size == (b).field ## _size && \
597 memcmp((a).field, (b).field, (a).field ## _size) == 0)
599 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
608 r
= dns_resource_key_equal(a
->key
, b
->key
);
612 if (a
->unparseable
!= b
->unparseable
)
615 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
618 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
622 return a
->srv
.priority
== b
->srv
.priority
&&
623 a
->srv
.weight
== b
->srv
.weight
&&
624 a
->srv
.port
== b
->srv
.port
;
630 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
633 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
634 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
636 case DNS_TYPE_SPF
: /* exactly the same as TXT */
638 return dns_txt_item_equal(a
->txt
.items
, b
->txt
.items
);
641 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
644 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
647 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
650 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
654 return a
->soa
.serial
== b
->soa
.serial
&&
655 a
->soa
.refresh
== b
->soa
.refresh
&&
656 a
->soa
.retry
== b
->soa
.retry
&&
657 a
->soa
.expire
== b
->soa
.expire
&&
658 a
->soa
.minimum
== b
->soa
.minimum
;
661 if (a
->mx
.priority
!= b
->mx
.priority
)
664 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
667 assert(a
->loc
.version
== b
->loc
.version
);
669 return a
->loc
.size
== b
->loc
.size
&&
670 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
671 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
672 a
->loc
.latitude
== b
->loc
.latitude
&&
673 a
->loc
.longitude
== b
->loc
.longitude
&&
674 a
->loc
.altitude
== b
->loc
.altitude
;
677 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
678 a
->ds
.algorithm
== b
->ds
.algorithm
&&
679 a
->ds
.digest_type
== b
->ds
.digest_type
&&
680 FIELD_EQUAL(a
->ds
, b
->ds
, digest
);
683 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
684 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
685 FIELD_EQUAL(a
->sshfp
, b
->sshfp
, fingerprint
);
687 case DNS_TYPE_DNSKEY
:
688 return a
->dnskey
.flags
== b
->dnskey
.flags
&&
689 a
->dnskey
.protocol
== b
->dnskey
.protocol
&&
690 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
691 FIELD_EQUAL(a
->dnskey
, b
->dnskey
, key
);
694 /* do the fast comparisons first */
695 return a
->rrsig
.type_covered
== b
->rrsig
.type_covered
&&
696 a
->rrsig
.algorithm
== b
->rrsig
.algorithm
&&
697 a
->rrsig
.labels
== b
->rrsig
.labels
&&
698 a
->rrsig
.original_ttl
== b
->rrsig
.original_ttl
&&
699 a
->rrsig
.expiration
== b
->rrsig
.expiration
&&
700 a
->rrsig
.inception
== b
->rrsig
.inception
&&
701 a
->rrsig
.key_tag
== b
->rrsig
.key_tag
&&
702 FIELD_EQUAL(a
->rrsig
, b
->rrsig
, signature
) &&
703 dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
706 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
707 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
710 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
711 a
->nsec3
.flags
== b
->nsec3
.flags
&&
712 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
713 FIELD_EQUAL(a
->nsec3
, b
->nsec3
, salt
) &&
714 FIELD_EQUAL(a
->nsec3
, b
->nsec3
, next_hashed_name
) &&
715 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
718 return a
->tlsa
.cert_usage
== b
->tlsa
.cert_usage
&&
719 a
->tlsa
.selector
== b
->tlsa
.selector
&&
720 a
->tlsa
.matching_type
== b
->tlsa
.matching_type
&&
721 FIELD_EQUAL(a
->tlsa
, b
->tlsa
, data
);
724 return a
->caa
.flags
== b
->caa
.flags
&&
725 streq(a
->caa
.tag
, b
->caa
.tag
) &&
726 FIELD_EQUAL(a
->caa
, b
->caa
, value
);
728 case DNS_TYPE_OPENPGPKEY
:
730 return FIELD_EQUAL(a
->generic
, b
->generic
, data
);
734 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
735 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
737 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
738 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
740 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
741 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
742 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
743 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
744 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
745 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
747 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
750 (lat
% 60000) / 1000.,
754 (lon
% 60000) / 1000.,
765 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
769 assert(l
> strlen("YYYYMMDDHHmmSS"));
771 if (!gmtime_r(&sec
, &tm
))
774 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
780 static char *format_types(Bitmap
*types
) {
781 _cleanup_strv_free_
char **strv
= NULL
;
782 _cleanup_free_
char *str
= NULL
;
787 BITMAP_FOREACH(type
, types
, i
) {
788 if (dns_type_to_string(type
)) {
789 r
= strv_extend(&strv
, dns_type_to_string(type
));
795 r
= asprintf(&t
, "TYPE%u", type
);
799 r
= strv_consume(&strv
, t
);
805 str
= strv_join(strv
, " ");
809 return strjoin("( ", str
, " )");
812 static char *format_txt(DnsTxtItem
*first
) {
817 LIST_FOREACH(items
, i
, first
)
818 c
+= i
->length
* 4 + 3;
820 p
= s
= new(char, c
);
824 LIST_FOREACH(items
, i
, first
) {
832 for (j
= 0; j
< i
->length
; j
++) {
833 if (i
->data
[j
] < ' ' || i
->data
[j
] == '"' || i
->data
[j
] >= 127) {
835 *(p
++) = '0' + (i
->data
[j
] / 100);
836 *(p
++) = '0' + ((i
->data
[j
] / 10) % 10);
837 *(p
++) = '0' + (i
->data
[j
] % 10);
849 const char *dns_resource_record_to_string(DnsResourceRecord
*rr
) {
850 _cleanup_free_
char *t
= NULL
;
851 char *s
, k
[DNS_RESOURCE_KEY_STRING_MAX
];
857 return rr
->to_string
;
859 dns_resource_key_to_string(rr
->key
, k
, sizeof(k
));
861 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
864 r
= asprintf(&s
, "%s %u %u %u %s",
869 strna(rr
->srv
.name
));
878 s
= strjoin(k
, " ", rr
->ptr
.name
);
885 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
);
890 case DNS_TYPE_SPF
: /* exactly the same as TXT */
892 t
= format_txt(rr
->txt
.items
);
896 s
= strjoin(k
, " ", t
);
902 _cleanup_free_
char *x
= NULL
;
904 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
908 s
= strjoin(k
, " ", x
);
915 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
919 s
= strjoin(k
, " ", t
);
925 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
927 strna(rr
->soa
.mname
),
928 strna(rr
->soa
.rname
),
939 r
= asprintf(&s
, "%s %u %s",
948 assert(rr
->loc
.version
== 0);
950 t
= format_location(rr
->loc
.latitude
,
959 s
= strjoin(k
, " ", t
);
965 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
969 r
= asprintf(&s
, "%s %u %u %u %s",
980 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
984 r
= asprintf(&s
, "%s %u %u %s",
993 case DNS_TYPE_DNSKEY
: {
994 _cleanup_free_
char *alg
= NULL
;
999 key_tag
= dnssec_keytag(rr
, true);
1001 r
= dnssec_algorithm_to_string_alloc(rr
->dnskey
.algorithm
, &alg
);
1005 r
= asprintf(&s
, "%s %u %u %s %n",
1008 rr
->dnskey
.protocol
,
1014 r
= base64_append(&s
, n
,
1015 rr
->dnskey
.key
, rr
->dnskey
.key_size
,
1020 r
= asprintf(&ss
, "%s\n"
1021 " -- Flags:%s%s%s\n"
1024 rr
->dnskey
.flags
& DNSKEY_FLAG_SEP
? " SEP" : "",
1025 rr
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
? " REVOKE" : "",
1026 rr
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
? " ZONE_KEY" : "",
1036 case DNS_TYPE_RRSIG
: {
1037 _cleanup_free_
char *alg
= NULL
;
1038 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
1042 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
1044 r
= dnssec_algorithm_to_string_alloc(rr
->rrsig
.algorithm
, &alg
);
1048 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
1052 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
1057 * http://tools.ietf.org/html/rfc3597#section-5 */
1059 r
= asprintf(&s
, "%s %s%.*u %s %u %u %s %s %u %s %n",
1062 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
1065 rr
->rrsig
.original_ttl
,
1074 r
= base64_append(&s
, n
,
1075 rr
->rrsig
.signature
, rr
->rrsig
.signature_size
,
1084 t
= format_types(rr
->nsec
.types
);
1088 r
= asprintf(&s
, "%s %s %s",
1090 rr
->nsec
.next_domain_name
,
1096 case DNS_TYPE_NSEC3
: {
1097 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
1099 if (rr
->nsec3
.salt_size
> 0) {
1100 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
1105 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
1109 t
= format_types(rr
->nsec3
.types
);
1113 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
1115 rr
->nsec3
.algorithm
,
1117 rr
->nsec3
.iterations
,
1118 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
1127 case DNS_TYPE_TLSA
: {
1128 const char *cert_usage
, *selector
, *matching_type
;
1130 cert_usage
= tlsa_cert_usage_to_string(rr
->tlsa
.cert_usage
);
1131 selector
= tlsa_selector_to_string(rr
->tlsa
.selector
);
1132 matching_type
= tlsa_matching_type_to_string(rr
->tlsa
.matching_type
);
1134 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
1140 " -- Cert. usage: %s\n"
1141 " -- Selector: %s\n"
1142 " -- Matching type: %s",
1144 rr
->tlsa
.cert_usage
,
1146 rr
->tlsa
.matching_type
,
1157 case DNS_TYPE_CAA
: {
1158 _cleanup_free_
char *value
;
1160 value
= octescape(rr
->caa
.value
, rr
->caa
.value_size
);
1164 r
= asprintf(&s
, "%s %u %s \"%s\"%s%s%s%.0u",
1169 rr
->caa
.flags
? "\n -- Flags:" : "",
1170 rr
->caa
.flags
& CAA_FLAG_CRITICAL
? " critical" : "",
1171 rr
->caa
.flags
& ~CAA_FLAG_CRITICAL
? " " : "",
1172 rr
->caa
.flags
& ~CAA_FLAG_CRITICAL
);
1179 case DNS_TYPE_OPENPGPKEY
: {
1182 r
= asprintf(&s
, "%s %n",
1188 r
= base64_append(&s
, n
,
1189 rr
->generic
.data
, rr
->generic
.data_size
,
1197 t
= hexmem(rr
->generic
.data
, rr
->generic
.data_size
);
1201 /* Format as documented in RFC 3597, Section 5 */
1202 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.data_size
, t
);
1212 ssize_t
dns_resource_record_payload(DnsResourceRecord
*rr
, void **out
) {
1216 switch(rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
1220 case DNS_TYPE_CNAME
:
1221 case DNS_TYPE_DNAME
:
1222 case DNS_TYPE_HINFO
:
1231 case DNS_TYPE_DNSKEY
:
1232 case DNS_TYPE_RRSIG
:
1234 case DNS_TYPE_NSEC3
:
1237 case DNS_TYPE_SSHFP
:
1238 *out
= rr
->sshfp
.fingerprint
;
1239 return rr
->sshfp
.fingerprint_size
;
1242 *out
= rr
->tlsa
.data
;
1243 return rr
->tlsa
.data_size
;
1246 case DNS_TYPE_OPENPGPKEY
:
1248 *out
= rr
->generic
.data
;
1249 return rr
->generic
.data_size
;
1253 int dns_resource_record_to_wire_format(DnsResourceRecord
*rr
, bool canonical
) {
1255 DnsPacket packet
= {
1257 .protocol
= DNS_PROTOCOL_DNS
,
1259 .refuse_compression
= true,
1260 .canonical_form
= canonical
,
1268 /* Generates the RR in wire-format, optionally in the
1269 * canonical form as discussed in the DNSSEC RFC 4034, Section
1270 * 6.2. We allocate a throw-away DnsPacket object on the stack
1271 * here, because we need some book-keeping for memory
1272 * management, and can reuse the DnsPacket serializer, that
1273 * can generate the canonical form, too, but also knows label
1274 * compression and suchlike. */
1276 if (rr
->wire_format
&& rr
->wire_format_canonical
== canonical
)
1279 r
= dns_packet_append_rr(&packet
, rr
, 0, &start
, &rds
);
1284 assert(packet
._data
);
1286 free(rr
->wire_format
);
1287 rr
->wire_format
= packet
._data
;
1288 rr
->wire_format_size
= packet
.size
;
1289 rr
->wire_format_rdata_offset
= rds
;
1290 rr
->wire_format_canonical
= canonical
;
1292 packet
._data
= NULL
;
1293 dns_packet_unref(&packet
);
1298 int dns_resource_record_signer(DnsResourceRecord
*rr
, const char **ret
) {
1305 /* Returns the RRset's signer, if it is known. */
1307 if (rr
->n_skip_labels_signer
== (unsigned) -1)
1310 n
= dns_resource_key_name(rr
->key
);
1311 r
= dns_name_skip(n
, rr
->n_skip_labels_signer
, &n
);
1321 int dns_resource_record_source(DnsResourceRecord
*rr
, const char **ret
) {
1328 /* Returns the RRset's synthesizing source, if it is known. */
1330 if (rr
->n_skip_labels_source
== (unsigned) -1)
1333 n
= dns_resource_key_name(rr
->key
);
1334 r
= dns_name_skip(n
, rr
->n_skip_labels_source
, &n
);
1344 int dns_resource_record_is_signer(DnsResourceRecord
*rr
, const char *zone
) {
1350 r
= dns_resource_record_signer(rr
, &signer
);
1354 return dns_name_equal(zone
, signer
);
1357 int dns_resource_record_is_synthetic(DnsResourceRecord
*rr
) {
1362 /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */
1364 if (rr
->n_skip_labels_source
== (unsigned) -1)
1367 if (rr
->n_skip_labels_source
== 0)
1370 if (rr
->n_skip_labels_source
> 1)
1373 r
= dns_name_startswith(dns_resource_key_name(rr
->key
), "*");
1380 void dns_resource_record_hash_func(const void *i
, struct siphash
*state
) {
1381 const DnsResourceRecord
*rr
= i
;
1385 dns_resource_key_hash_func(rr
->key
, state
);
1387 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
1390 siphash24_compress(&rr
->srv
.priority
, sizeof(rr
->srv
.priority
), state
);
1391 siphash24_compress(&rr
->srv
.weight
, sizeof(rr
->srv
.weight
), state
);
1392 siphash24_compress(&rr
->srv
.port
, sizeof(rr
->srv
.port
), state
);
1393 dns_name_hash_func(rr
->srv
.name
, state
);
1398 case DNS_TYPE_CNAME
:
1399 case DNS_TYPE_DNAME
:
1400 dns_name_hash_func(rr
->ptr
.name
, state
);
1403 case DNS_TYPE_HINFO
:
1404 string_hash_func(rr
->hinfo
.cpu
, state
);
1405 string_hash_func(rr
->hinfo
.os
, state
);
1409 case DNS_TYPE_SPF
: {
1412 LIST_FOREACH(items
, j
, rr
->txt
.items
) {
1413 siphash24_compress(j
->data
, j
->length
, state
);
1415 /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab"
1416 * followed by "". */
1417 siphash24_compress_byte(0, state
);
1423 siphash24_compress(&rr
->a
.in_addr
, sizeof(rr
->a
.in_addr
), state
);
1427 siphash24_compress(&rr
->aaaa
.in6_addr
, sizeof(rr
->aaaa
.in6_addr
), state
);
1431 dns_name_hash_func(rr
->soa
.mname
, state
);
1432 dns_name_hash_func(rr
->soa
.rname
, state
);
1433 siphash24_compress(&rr
->soa
.serial
, sizeof(rr
->soa
.serial
), state
);
1434 siphash24_compress(&rr
->soa
.refresh
, sizeof(rr
->soa
.refresh
), state
);
1435 siphash24_compress(&rr
->soa
.retry
, sizeof(rr
->soa
.retry
), state
);
1436 siphash24_compress(&rr
->soa
.expire
, sizeof(rr
->soa
.expire
), state
);
1437 siphash24_compress(&rr
->soa
.minimum
, sizeof(rr
->soa
.minimum
), state
);
1441 siphash24_compress(&rr
->mx
.priority
, sizeof(rr
->mx
.priority
), state
);
1442 dns_name_hash_func(rr
->mx
.exchange
, state
);
1446 siphash24_compress(&rr
->loc
.version
, sizeof(rr
->loc
.version
), state
);
1447 siphash24_compress(&rr
->loc
.size
, sizeof(rr
->loc
.size
), state
);
1448 siphash24_compress(&rr
->loc
.horiz_pre
, sizeof(rr
->loc
.horiz_pre
), state
);
1449 siphash24_compress(&rr
->loc
.vert_pre
, sizeof(rr
->loc
.vert_pre
), state
);
1450 siphash24_compress(&rr
->loc
.latitude
, sizeof(rr
->loc
.latitude
), state
);
1451 siphash24_compress(&rr
->loc
.longitude
, sizeof(rr
->loc
.longitude
), state
);
1452 siphash24_compress(&rr
->loc
.altitude
, sizeof(rr
->loc
.altitude
), state
);
1455 case DNS_TYPE_SSHFP
:
1456 siphash24_compress(&rr
->sshfp
.algorithm
, sizeof(rr
->sshfp
.algorithm
), state
);
1457 siphash24_compress(&rr
->sshfp
.fptype
, sizeof(rr
->sshfp
.fptype
), state
);
1458 siphash24_compress(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
, state
);
1461 case DNS_TYPE_DNSKEY
:
1462 siphash24_compress(&rr
->dnskey
.flags
, sizeof(rr
->dnskey
.flags
), state
);
1463 siphash24_compress(&rr
->dnskey
.protocol
, sizeof(rr
->dnskey
.protocol
), state
);
1464 siphash24_compress(&rr
->dnskey
.algorithm
, sizeof(rr
->dnskey
.algorithm
), state
);
1465 siphash24_compress(rr
->dnskey
.key
, rr
->dnskey
.key_size
, state
);
1468 case DNS_TYPE_RRSIG
:
1469 siphash24_compress(&rr
->rrsig
.type_covered
, sizeof(rr
->rrsig
.type_covered
), state
);
1470 siphash24_compress(&rr
->rrsig
.algorithm
, sizeof(rr
->rrsig
.algorithm
), state
);
1471 siphash24_compress(&rr
->rrsig
.labels
, sizeof(rr
->rrsig
.labels
), state
);
1472 siphash24_compress(&rr
->rrsig
.original_ttl
, sizeof(rr
->rrsig
.original_ttl
), state
);
1473 siphash24_compress(&rr
->rrsig
.expiration
, sizeof(rr
->rrsig
.expiration
), state
);
1474 siphash24_compress(&rr
->rrsig
.inception
, sizeof(rr
->rrsig
.inception
), state
);
1475 siphash24_compress(&rr
->rrsig
.key_tag
, sizeof(rr
->rrsig
.key_tag
), state
);
1476 dns_name_hash_func(rr
->rrsig
.signer
, state
);
1477 siphash24_compress(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
, state
);
1481 dns_name_hash_func(rr
->nsec
.next_domain_name
, state
);
1482 /* FIXME: we leave out the type bitmap here. Hash
1483 * would be better if we'd take it into account
1488 siphash24_compress(&rr
->ds
.key_tag
, sizeof(rr
->ds
.key_tag
), state
);
1489 siphash24_compress(&rr
->ds
.algorithm
, sizeof(rr
->ds
.algorithm
), state
);
1490 siphash24_compress(&rr
->ds
.digest_type
, sizeof(rr
->ds
.digest_type
), state
);
1491 siphash24_compress(rr
->ds
.digest
, rr
->ds
.digest_size
, state
);
1494 case DNS_TYPE_NSEC3
:
1495 siphash24_compress(&rr
->nsec3
.algorithm
, sizeof(rr
->nsec3
.algorithm
), state
);
1496 siphash24_compress(&rr
->nsec3
.flags
, sizeof(rr
->nsec3
.flags
), state
);
1497 siphash24_compress(&rr
->nsec3
.iterations
, sizeof(rr
->nsec3
.iterations
), state
);
1498 siphash24_compress(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
, state
);
1499 siphash24_compress(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, state
);
1500 /* FIXME: We leave the bitmaps out */
1504 siphash24_compress(&rr
->tlsa
.cert_usage
, sizeof(rr
->tlsa
.cert_usage
), state
);
1505 siphash24_compress(&rr
->tlsa
.selector
, sizeof(rr
->tlsa
.selector
), state
);
1506 siphash24_compress(&rr
->tlsa
.matching_type
, sizeof(rr
->tlsa
.matching_type
), state
);
1507 siphash24_compress(rr
->tlsa
.data
, rr
->tlsa
.data_size
, state
);
1511 siphash24_compress(&rr
->caa
.flags
, sizeof(rr
->caa
.flags
), state
);
1512 string_hash_func(rr
->caa
.tag
, state
);
1513 siphash24_compress(rr
->caa
.value
, rr
->caa
.value_size
, state
);
1516 case DNS_TYPE_OPENPGPKEY
:
1518 siphash24_compress(rr
->generic
.data
, rr
->generic
.data_size
, state
);
1523 static int dns_resource_record_compare_func(const void *a
, const void *b
) {
1524 const DnsResourceRecord
*x
= a
, *y
= b
;
1527 ret
= dns_resource_key_compare_func(x
->key
, y
->key
);
1531 if (dns_resource_record_equal(x
, y
))
1534 /* This is a bit dirty, we don't implement proper ordering, but
1535 * the hashtable doesn't need ordering anyway, hence we don't
1537 return x
< y
? -1 : 1;
1540 const struct hash_ops dns_resource_record_hash_ops
= {
1541 .hash
= dns_resource_record_hash_func
,
1542 .compare
= dns_resource_record_compare_func
,
1545 DnsResourceRecord
*dns_resource_record_copy(DnsResourceRecord
*rr
) {
1546 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*copy
= NULL
;
1547 DnsResourceRecord
*t
;
1551 copy
= dns_resource_record_new(rr
->key
);
1555 copy
->ttl
= rr
->ttl
;
1556 copy
->expiry
= rr
->expiry
;
1557 copy
->n_skip_labels_signer
= rr
->n_skip_labels_signer
;
1558 copy
->n_skip_labels_source
= rr
->n_skip_labels_source
;
1559 copy
->unparseable
= rr
->unparseable
;
1561 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
1564 copy
->srv
.priority
= rr
->srv
.priority
;
1565 copy
->srv
.weight
= rr
->srv
.weight
;
1566 copy
->srv
.port
= rr
->srv
.port
;
1567 copy
->srv
.name
= strdup(rr
->srv
.name
);
1568 if (!copy
->srv
.name
)
1574 case DNS_TYPE_CNAME
:
1575 case DNS_TYPE_DNAME
:
1576 copy
->ptr
.name
= strdup(rr
->ptr
.name
);
1577 if (!copy
->ptr
.name
)
1581 case DNS_TYPE_HINFO
:
1582 copy
->hinfo
.cpu
= strdup(rr
->hinfo
.cpu
);
1583 if (!copy
->hinfo
.cpu
)
1586 copy
->hinfo
.os
= strdup(rr
->hinfo
.os
);
1587 if (!copy
->hinfo
.os
)
1593 copy
->txt
.items
= dns_txt_item_copy(rr
->txt
.items
);
1594 if (!copy
->txt
.items
)
1603 copy
->aaaa
= rr
->aaaa
;
1607 copy
->soa
.mname
= strdup(rr
->soa
.mname
);
1608 if (!copy
->soa
.mname
)
1610 copy
->soa
.rname
= strdup(rr
->soa
.rname
);
1611 if (!copy
->soa
.rname
)
1613 copy
->soa
.serial
= rr
->soa
.serial
;
1614 copy
->soa
.refresh
= rr
->soa
.refresh
;
1615 copy
->soa
.retry
= rr
->soa
.retry
;
1616 copy
->soa
.expire
= rr
->soa
.expire
;
1617 copy
->soa
.minimum
= rr
->soa
.minimum
;
1621 copy
->mx
.priority
= rr
->mx
.priority
;
1622 copy
->mx
.exchange
= strdup(rr
->mx
.exchange
);
1623 if (!copy
->mx
.exchange
)
1628 copy
->loc
= rr
->loc
;
1631 case DNS_TYPE_SSHFP
:
1632 copy
->sshfp
.algorithm
= rr
->sshfp
.algorithm
;
1633 copy
->sshfp
.fptype
= rr
->sshfp
.fptype
;
1634 copy
->sshfp
.fingerprint
= memdup(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
1635 if (!copy
->sshfp
.fingerprint
)
1637 copy
->sshfp
.fingerprint_size
= rr
->sshfp
.fingerprint_size
;
1640 case DNS_TYPE_DNSKEY
:
1641 copy
->dnskey
.flags
= rr
->dnskey
.flags
;
1642 copy
->dnskey
.protocol
= rr
->dnskey
.protocol
;
1643 copy
->dnskey
.algorithm
= rr
->dnskey
.algorithm
;
1644 copy
->dnskey
.key
= memdup(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
1645 if (!copy
->dnskey
.key
)
1647 copy
->dnskey
.key_size
= rr
->dnskey
.key_size
;
1650 case DNS_TYPE_RRSIG
:
1651 copy
->rrsig
.type_covered
= rr
->rrsig
.type_covered
;
1652 copy
->rrsig
.algorithm
= rr
->rrsig
.algorithm
;
1653 copy
->rrsig
.labels
= rr
->rrsig
.labels
;
1654 copy
->rrsig
.original_ttl
= rr
->rrsig
.original_ttl
;
1655 copy
->rrsig
.expiration
= rr
->rrsig
.expiration
;
1656 copy
->rrsig
.inception
= rr
->rrsig
.inception
;
1657 copy
->rrsig
.key_tag
= rr
->rrsig
.key_tag
;
1658 copy
->rrsig
.signer
= strdup(rr
->rrsig
.signer
);
1659 if (!copy
->rrsig
.signer
)
1661 copy
->rrsig
.signature
= memdup(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
1662 if (!copy
->rrsig
.signature
)
1664 copy
->rrsig
.signature_size
= rr
->rrsig
.signature_size
;
1668 copy
->nsec
.next_domain_name
= strdup(rr
->nsec
.next_domain_name
);
1669 if (!copy
->nsec
.next_domain_name
)
1671 copy
->nsec
.types
= bitmap_copy(rr
->nsec
.types
);
1672 if (!copy
->nsec
.types
)
1677 copy
->ds
.key_tag
= rr
->ds
.key_tag
;
1678 copy
->ds
.algorithm
= rr
->ds
.algorithm
;
1679 copy
->ds
.digest_type
= rr
->ds
.digest_type
;
1680 copy
->ds
.digest
= memdup(rr
->ds
.digest
, rr
->ds
.digest_size
);
1681 if (!copy
->ds
.digest
)
1683 copy
->ds
.digest_size
= rr
->ds
.digest_size
;
1686 case DNS_TYPE_NSEC3
:
1687 copy
->nsec3
.algorithm
= rr
->nsec3
.algorithm
;
1688 copy
->nsec3
.flags
= rr
->nsec3
.flags
;
1689 copy
->nsec3
.iterations
= rr
->nsec3
.iterations
;
1690 copy
->nsec3
.salt
= memdup(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
1691 if (!copy
->nsec3
.salt
)
1693 copy
->nsec3
.salt_size
= rr
->nsec3
.salt_size
;
1694 copy
->nsec3
.next_hashed_name
= memdup(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
);
1695 if (!copy
->nsec3
.next_hashed_name_size
)
1697 copy
->nsec3
.next_hashed_name_size
= rr
->nsec3
.next_hashed_name_size
;
1698 copy
->nsec3
.types
= bitmap_copy(rr
->nsec3
.types
);
1699 if (!copy
->nsec3
.types
)
1704 copy
->tlsa
.cert_usage
= rr
->tlsa
.cert_usage
;
1705 copy
->tlsa
.selector
= rr
->tlsa
.selector
;
1706 copy
->tlsa
.matching_type
= rr
->tlsa
.matching_type
;
1707 copy
->tlsa
.data
= memdup(rr
->tlsa
.data
, rr
->tlsa
.data_size
);
1708 if (!copy
->tlsa
.data
)
1710 copy
->tlsa
.data_size
= rr
->tlsa
.data_size
;
1714 copy
->caa
.flags
= rr
->caa
.flags
;
1715 copy
->caa
.tag
= strdup(rr
->caa
.tag
);
1718 copy
->caa
.value
= memdup(rr
->caa
.value
, rr
->caa
.value_size
);
1719 if (!copy
->caa
.value
)
1721 copy
->caa
.value_size
= rr
->caa
.value_size
;
1726 copy
->generic
.data
= memdup(rr
->generic
.data
, rr
->generic
.data_size
);
1727 if (!copy
->generic
.data
)
1729 copy
->generic
.data_size
= rr
->generic
.data_size
;
1739 int dns_resource_record_clamp_ttl(DnsResourceRecord
**rr
, uint32_t max_ttl
) {
1740 DnsResourceRecord
*old_rr
, *new_rr
;
1746 if (old_rr
->key
->type
== DNS_TYPE_OPT
)
1749 new_ttl
= MIN(old_rr
->ttl
, max_ttl
);
1750 if (new_ttl
== old_rr
->ttl
)
1753 if (old_rr
->n_ref
== 1) {
1754 /* Patch in place */
1755 old_rr
->ttl
= new_ttl
;
1759 new_rr
= dns_resource_record_copy(old_rr
);
1763 new_rr
->ttl
= new_ttl
;
1765 dns_resource_record_unref(*rr
);
1771 DnsTxtItem
*dns_txt_item_free_all(DnsTxtItem
*i
) {
1780 return dns_txt_item_free_all(n
);
1783 bool dns_txt_item_equal(DnsTxtItem
*a
, DnsTxtItem
*b
) {
1794 if (a
->length
!= b
->length
)
1797 if (memcmp(a
->data
, b
->data
, a
->length
) != 0)
1800 return dns_txt_item_equal(a
->items_next
, b
->items_next
);
1803 DnsTxtItem
*dns_txt_item_copy(DnsTxtItem
*first
) {
1804 DnsTxtItem
*i
, *copy
= NULL
, *end
= NULL
;
1806 LIST_FOREACH(items
, i
, first
) {
1809 j
= memdup(i
, offsetof(DnsTxtItem
, data
) + i
->length
+ 1);
1811 dns_txt_item_free_all(copy
);
1815 LIST_INSERT_AFTER(items
, copy
, end
, j
);
1822 int dns_txt_item_new_empty(DnsTxtItem
**ret
) {
1825 /* RFC 6763, section 6.1 suggests to treat
1826 * empty TXT RRs as equivalent to a TXT record
1827 * with a single empty string. */
1829 i
= malloc0(offsetof(DnsTxtItem
, data
) + 1); /* for safety reasons we add an extra NUL byte */
1838 static const char* const dnssec_algorithm_table
[_DNSSEC_ALGORITHM_MAX_DEFINED
] = {
1839 /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
1840 [DNSSEC_ALGORITHM_RSAMD5
] = "RSAMD5",
1841 [DNSSEC_ALGORITHM_DH
] = "DH",
1842 [DNSSEC_ALGORITHM_DSA
] = "DSA",
1843 [DNSSEC_ALGORITHM_ECC
] = "ECC",
1844 [DNSSEC_ALGORITHM_RSASHA1
] = "RSASHA1",
1845 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1
] = "DSA-NSEC3-SHA1",
1846 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
] = "RSASHA1-NSEC3-SHA1",
1847 [DNSSEC_ALGORITHM_RSASHA256
] = "RSASHA256",
1848 [DNSSEC_ALGORITHM_RSASHA512
] = "RSASHA512",
1849 [DNSSEC_ALGORITHM_ECC_GOST
] = "ECC-GOST",
1850 [DNSSEC_ALGORITHM_ECDSAP256SHA256
] = "ECDSAP256SHA256",
1851 [DNSSEC_ALGORITHM_ECDSAP384SHA384
] = "ECDSAP384SHA384",
1852 [DNSSEC_ALGORITHM_ED25519
] = "ED25519",
1853 [DNSSEC_ALGORITHM_ED448
] = "ED448",
1854 [DNSSEC_ALGORITHM_INDIRECT
] = "INDIRECT",
1855 [DNSSEC_ALGORITHM_PRIVATEDNS
] = "PRIVATEDNS",
1856 [DNSSEC_ALGORITHM_PRIVATEOID
] = "PRIVATEOID",
1858 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm
, int, 255);
1860 static const char* const dnssec_digest_table
[_DNSSEC_DIGEST_MAX_DEFINED
] = {
1861 /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
1862 [DNSSEC_DIGEST_SHA1
] = "SHA-1",
1863 [DNSSEC_DIGEST_SHA256
] = "SHA-256",
1864 [DNSSEC_DIGEST_GOST_R_34_11_94
] = "GOST_R_34.11-94",
1865 [DNSSEC_DIGEST_SHA384
] = "SHA-384",
1867 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest
, int, 255);