1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "alloc-util.h"
6 #include "dns-domain.h"
10 #include "memory-util.h"
11 #include "resolved-dns-dnssec.h"
12 #include "resolved-dns-packet.h"
13 #include "resolved-dns-rr.h"
14 #include "string-table.h"
15 #include "string-util.h"
17 #include "terminal-util.h"
19 DnsResourceKey
* dns_resource_key_new(uint16_t class, uint16_t type
, const char *name
) {
26 k
= malloc0(sizeof(DnsResourceKey
) + l
+ 1);
34 strcpy((char*) k
+ sizeof(DnsResourceKey
), name
);
39 DnsResourceKey
* dns_resource_key_new_redirect(const DnsResourceKey
*key
, const DnsResourceRecord
*cname
) {
45 assert(IN_SET(cname
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
));
47 if (cname
->key
->type
== DNS_TYPE_CNAME
)
48 return dns_resource_key_new(key
->class, key
->type
, cname
->cname
.name
);
51 char *destination
= NULL
;
53 r
= dns_name_change_suffix(dns_resource_key_name(key
), dns_resource_key_name(cname
->key
), cname
->dname
.name
, &destination
);
57 return dns_resource_key_ref((DnsResourceKey
*) key
);
59 k
= dns_resource_key_new_consume(key
->class, key
->type
, destination
);
61 return mfree(destination
);
67 int dns_resource_key_new_append_suffix(DnsResourceKey
**ret
, DnsResourceKey
*key
, char *name
) {
68 DnsResourceKey
*new_key
;
76 if (dns_name_is_root(name
)) {
77 *ret
= dns_resource_key_ref(key
);
81 r
= dns_name_concat(dns_resource_key_name(key
), name
, 0, &joined
);
85 new_key
= dns_resource_key_new_consume(key
->class, key
->type
, joined
);
95 DnsResourceKey
* dns_resource_key_new_consume(uint16_t class, uint16_t type
, char *name
) {
100 k
= new(DnsResourceKey
, 1);
104 *k
= (DnsResourceKey
) {
114 DnsResourceKey
* dns_resource_key_ref(DnsResourceKey
*k
) {
119 /* Static/const keys created with DNS_RESOURCE_KEY_CONST will
120 * set this to -1, they should not be reffed/unreffed */
121 assert(k
->n_ref
!= UINT_MAX
);
123 assert(k
->n_ref
> 0);
129 DnsResourceKey
* dns_resource_key_unref(DnsResourceKey
*k
) {
133 assert(k
->n_ref
!= UINT_MAX
);
134 assert(k
->n_ref
> 0);
145 const char* dns_resource_key_name(const DnsResourceKey
*key
) {
154 name
= (char*) key
+ sizeof(DnsResourceKey
);
156 if (dns_name_is_root(name
))
162 bool dns_resource_key_is_address(const DnsResourceKey
*key
) {
165 /* Check if this is an A or AAAA resource key */
167 return key
->class == DNS_CLASS_IN
&& IN_SET(key
->type
, DNS_TYPE_A
, DNS_TYPE_AAAA
);
170 bool dns_resource_key_is_dnssd_ptr(const DnsResourceKey
*key
) {
173 /* Check if this is a PTR resource key used in
174 Service Instance Enumeration as described in RFC6763 p4.1. */
176 if (key
->type
!= DNS_TYPE_PTR
)
179 return dns_name_endswith(dns_resource_key_name(key
), "_tcp.local") ||
180 dns_name_endswith(dns_resource_key_name(key
), "_udp.local");
183 int dns_resource_key_equal(const DnsResourceKey
*a
, const DnsResourceKey
*b
) {
189 r
= dns_name_equal(dns_resource_key_name(a
), dns_resource_key_name(b
));
193 if (a
->class != b
->class)
196 if (a
->type
!= b
->type
)
202 int dns_resource_key_match_rr(const DnsResourceKey
*key
, DnsResourceRecord
*rr
, const char *search_domain
) {
211 /* Checks if an rr matches the specified key. If a search
212 * domain is specified, it will also be checked if the key
213 * with the search domain suffixed might match the RR. */
215 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
218 if (rr
->key
->type
!= key
->type
&& key
->type
!= DNS_TYPE_ANY
)
221 r
= dns_name_equal(dns_resource_key_name(rr
->key
), dns_resource_key_name(key
));
226 _cleanup_free_
char *joined
= NULL
;
228 r
= dns_name_concat(dns_resource_key_name(key
), search_domain
, 0, &joined
);
232 return dns_name_equal(dns_resource_key_name(rr
->key
), joined
);
238 int dns_resource_key_match_cname_or_dname(const DnsResourceKey
*key
, const DnsResourceKey
*cname
, const char *search_domain
) {
244 if (cname
->class != key
->class && key
->class != DNS_CLASS_ANY
)
247 if (!dns_type_may_redirect(key
->type
))
250 if (cname
->type
== DNS_TYPE_CNAME
)
251 r
= dns_name_equal(dns_resource_key_name(key
), dns_resource_key_name(cname
));
252 else if (cname
->type
== DNS_TYPE_DNAME
)
253 r
= dns_name_endswith(dns_resource_key_name(key
), dns_resource_key_name(cname
));
261 _cleanup_free_
char *joined
= NULL
;
263 r
= dns_name_concat(dns_resource_key_name(key
), search_domain
, 0, &joined
);
267 if (cname
->type
== DNS_TYPE_CNAME
)
268 return dns_name_equal(joined
, dns_resource_key_name(cname
));
269 else if (cname
->type
== DNS_TYPE_DNAME
)
270 return dns_name_endswith(joined
, dns_resource_key_name(cname
));
276 int dns_resource_key_match_soa(const DnsResourceKey
*key
, const DnsResourceKey
*soa
) {
280 /* Checks whether 'soa' is a SOA record for the specified key. */
282 if (soa
->class != key
->class)
285 if (soa
->type
!= DNS_TYPE_SOA
)
288 return dns_name_endswith(dns_resource_key_name(key
), dns_resource_key_name(soa
));
291 static void dns_resource_key_hash_func(const DnsResourceKey
*k
, struct siphash
*state
) {
294 dns_name_hash_func(dns_resource_key_name(k
), state
);
295 siphash24_compress(&k
->class, sizeof(k
->class), state
);
296 siphash24_compress(&k
->type
, sizeof(k
->type
), state
);
299 static int dns_resource_key_compare_func(const DnsResourceKey
*x
, const DnsResourceKey
*y
) {
302 r
= dns_name_compare_func(dns_resource_key_name(x
), dns_resource_key_name(y
));
306 r
= CMP(x
->type
, y
->type
);
310 return CMP(x
->class, y
->class);
313 DEFINE_HASH_OPS(dns_resource_key_hash_ops
, DnsResourceKey
, dns_resource_key_hash_func
, dns_resource_key_compare_func
);
315 char* dns_resource_key_to_string(const DnsResourceKey
*key
, char *buf
, size_t buf_size
) {
319 /* If we cannot convert the CLASS/TYPE into a known string,
320 use the format recommended by RFC 3597, Section 5. */
322 c
= dns_class_to_string(key
->class);
323 t
= dns_type_to_string(key
->type
);
325 snprintf(buf
, buf_size
, "%s %s%s%.0u %s%s%.0u",
326 dns_resource_key_name(key
),
327 strempty(c
), c
? "" : "CLASS", c
? 0 : key
->class,
328 strempty(t
), t
? "" : "TYPE", t
? 0 : key
->type
);
333 bool dns_resource_key_reduce(DnsResourceKey
**a
, DnsResourceKey
**b
) {
337 /* Try to replace one RR key by another if they are identical, thus saving a bit of memory. Note that we do
338 * this only for RR keys, not for RRs themselves, as they carry a lot of additional metadata (where they come
339 * from, validity data, and suchlike), and cannot be replaced so easily by other RRs that have the same
340 * superficial data. */
347 /* We refuse merging const keys */
348 if ((*a
)->n_ref
== UINT_MAX
)
350 if ((*b
)->n_ref
== UINT_MAX
)
353 /* Already the same? */
357 /* Are they really identical? */
358 if (dns_resource_key_equal(*a
, *b
) <= 0)
361 /* Keep the one which already has more references. */
362 if ((*a
)->n_ref
> (*b
)->n_ref
) {
363 dns_resource_key_unref(*b
);
364 *b
= dns_resource_key_ref(*a
);
366 dns_resource_key_unref(*a
);
367 *a
= dns_resource_key_ref(*b
);
373 DnsResourceRecord
* dns_resource_record_new(DnsResourceKey
*key
) {
374 DnsResourceRecord
*rr
;
376 rr
= new(DnsResourceRecord
, 1);
380 *rr
= (DnsResourceRecord
) {
382 .key
= dns_resource_key_ref(key
),
383 .expiry
= USEC_INFINITY
,
384 .n_skip_labels_signer
= UINT_MAX
,
385 .n_skip_labels_source
= UINT_MAX
,
391 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
392 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
394 key
= dns_resource_key_new(class, type
, name
);
398 return dns_resource_record_new(key
);
401 static DnsResourceRecord
* dns_resource_record_free(DnsResourceRecord
*rr
) {
405 switch(rr
->key
->type
) {
425 dns_txt_item_free_all(rr
->txt
.items
);
434 free(rr
->mx
.exchange
);
442 free(rr
->sshfp
.fingerprint
);
445 case DNS_TYPE_DNSKEY
:
446 free(rr
->dnskey
.key
);
450 free(rr
->rrsig
.signer
);
451 free(rr
->rrsig
.signature
);
455 free(rr
->nsec
.next_domain_name
);
456 bitmap_free(rr
->nsec
.types
);
460 free(rr
->nsec3
.next_hashed_name
);
461 free(rr
->nsec3
.salt
);
462 bitmap_free(rr
->nsec3
.types
);
479 case DNS_TYPE_OPENPGPKEY
:
482 free(rr
->generic
.data
);
486 free(rr
->generic
.data
);
488 free(rr
->wire_format
);
489 dns_resource_key_unref(rr
->key
);
496 DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsResourceRecord
, dns_resource_record
, dns_resource_record_free
);
498 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
499 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
500 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
501 _cleanup_free_
char *ptr
= NULL
;
508 r
= dns_name_reverse(family
, address
, &ptr
);
512 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
518 rr
= dns_resource_record_new(key
);
522 rr
->ptr
.name
= strdup(hostname
);
531 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
532 DnsResourceRecord
*rr
;
538 if (family
== AF_INET
) {
540 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
544 rr
->a
.in_addr
= address
->in
;
546 } else if (family
== AF_INET6
) {
548 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
552 rr
->aaaa
.in6_addr
= address
->in6
;
554 return -EAFNOSUPPORT
;
561 #define FIELD_EQUAL(a, b, field) \
562 ((a).field ## _size == (b).field ## _size && \
563 memcmp_safe((a).field, (b).field, (a).field ## _size) == 0)
565 int dns_resource_record_payload_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
568 /* Check if a and b are the same, but don't look at their keys */
570 if (a
->unparsable
!= b
->unparsable
)
573 switch (a
->unparsable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
576 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
580 return a
->srv
.priority
== b
->srv
.priority
&&
581 a
->srv
.weight
== b
->srv
.weight
&&
582 a
->srv
.port
== b
->srv
.port
;
588 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
591 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
592 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
594 case DNS_TYPE_SPF
: /* exactly the same as TXT */
596 return dns_txt_item_equal(a
->txt
.items
, b
->txt
.items
);
599 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
602 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
605 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
608 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
612 return a
->soa
.serial
== b
->soa
.serial
&&
613 a
->soa
.refresh
== b
->soa
.refresh
&&
614 a
->soa
.retry
== b
->soa
.retry
&&
615 a
->soa
.expire
== b
->soa
.expire
&&
616 a
->soa
.minimum
== b
->soa
.minimum
;
619 if (a
->mx
.priority
!= b
->mx
.priority
)
622 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
625 assert(a
->loc
.version
== b
->loc
.version
);
627 return a
->loc
.size
== b
->loc
.size
&&
628 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
629 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
630 a
->loc
.latitude
== b
->loc
.latitude
&&
631 a
->loc
.longitude
== b
->loc
.longitude
&&
632 a
->loc
.altitude
== b
->loc
.altitude
;
635 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
636 a
->ds
.algorithm
== b
->ds
.algorithm
&&
637 a
->ds
.digest_type
== b
->ds
.digest_type
&&
638 FIELD_EQUAL(a
->ds
, b
->ds
, digest
);
641 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
642 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
643 FIELD_EQUAL(a
->sshfp
, b
->sshfp
, fingerprint
);
645 case DNS_TYPE_DNSKEY
:
646 return a
->dnskey
.flags
== b
->dnskey
.flags
&&
647 a
->dnskey
.protocol
== b
->dnskey
.protocol
&&
648 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
649 FIELD_EQUAL(a
->dnskey
, b
->dnskey
, key
);
652 /* do the fast comparisons first */
653 return a
->rrsig
.type_covered
== b
->rrsig
.type_covered
&&
654 a
->rrsig
.algorithm
== b
->rrsig
.algorithm
&&
655 a
->rrsig
.labels
== b
->rrsig
.labels
&&
656 a
->rrsig
.original_ttl
== b
->rrsig
.original_ttl
&&
657 a
->rrsig
.expiration
== b
->rrsig
.expiration
&&
658 a
->rrsig
.inception
== b
->rrsig
.inception
&&
659 a
->rrsig
.key_tag
== b
->rrsig
.key_tag
&&
660 FIELD_EQUAL(a
->rrsig
, b
->rrsig
, signature
) &&
661 dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
664 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
665 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
668 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
669 a
->nsec3
.flags
== b
->nsec3
.flags
&&
670 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
671 FIELD_EQUAL(a
->nsec3
, b
->nsec3
, salt
) &&
672 FIELD_EQUAL(a
->nsec3
, b
->nsec3
, next_hashed_name
) &&
673 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
676 return a
->tlsa
.cert_usage
== b
->tlsa
.cert_usage
&&
677 a
->tlsa
.selector
== b
->tlsa
.selector
&&
678 a
->tlsa
.matching_type
== b
->tlsa
.matching_type
&&
679 FIELD_EQUAL(a
->tlsa
, b
->tlsa
, data
);
682 return a
->caa
.flags
== b
->caa
.flags
&&
683 streq(a
->caa
.tag
, b
->caa
.tag
) &&
684 FIELD_EQUAL(a
->caa
, b
->caa
, value
);
686 case DNS_TYPE_OPENPGPKEY
:
688 return FIELD_EQUAL(a
->generic
, b
->generic
, data
);
692 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
701 r
= dns_resource_key_equal(a
->key
, b
->key
);
705 return dns_resource_record_payload_equal(a
, b
);
708 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
709 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
711 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
712 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
714 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
715 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
716 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
717 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
718 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
719 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
721 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
724 (lat
% 60000) / 1000.,
728 (lon
% 60000) / 1000.,
739 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
743 assert(l
> STRLEN("YYYYMMDDHHmmSS"));
745 if (!gmtime_r(&sec
, &tm
))
748 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
754 static char *format_types(Bitmap
*types
) {
755 _cleanup_strv_free_
char **strv
= NULL
;
756 _cleanup_free_
char *str
= NULL
;
760 BITMAP_FOREACH(type
, types
) {
761 if (dns_type_to_string(type
)) {
762 r
= strv_extend(&strv
, dns_type_to_string(type
));
768 r
= asprintf(&t
, "TYPE%u", type
);
772 r
= strv_consume(&strv
, t
);
778 str
= strv_join(strv
, " ");
782 return strjoin("( ", str
, " )");
785 static char *format_txt(DnsTxtItem
*first
) {
790 LIST_FOREACH(items
, i
, first
)
791 c
+= i
->length
* 4 + 3;
793 p
= s
= new(char, c
);
797 LIST_FOREACH(items
, i
, first
) {
805 for (j
= 0; j
< i
->length
; j
++) {
806 if (i
->data
[j
] < ' ' || i
->data
[j
] == '"' || i
->data
[j
] >= 127) {
808 *(p
++) = '0' + (i
->data
[j
] / 100);
809 *(p
++) = '0' + ((i
->data
[j
] / 10) % 10);
810 *(p
++) = '0' + (i
->data
[j
] % 10);
822 const char *dns_resource_record_to_string(DnsResourceRecord
*rr
) {
823 _cleanup_free_
char *t
= NULL
;
824 char *s
, k
[DNS_RESOURCE_KEY_STRING_MAX
];
830 return rr
->to_string
;
832 dns_resource_key_to_string(rr
->key
, k
, sizeof(k
));
834 switch (rr
->unparsable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
837 r
= asprintf(&s
, "%s %u %u %u %s",
842 strna(rr
->srv
.name
));
851 s
= strjoin(k
, " ", rr
->ptr
.name
);
858 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
);
863 case DNS_TYPE_SPF
: /* exactly the same as TXT */
865 t
= format_txt(rr
->txt
.items
);
869 s
= strjoin(k
, " ", t
);
875 _cleanup_free_
char *x
= NULL
;
877 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
881 s
= strjoin(k
, " ", x
);
888 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
892 s
= strjoin(k
, " ", t
);
898 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
900 strna(rr
->soa
.mname
),
901 strna(rr
->soa
.rname
),
912 r
= asprintf(&s
, "%s %u %s",
921 assert(rr
->loc
.version
== 0);
923 t
= format_location(rr
->loc
.latitude
,
932 s
= strjoin(k
, " ", t
);
938 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
942 r
= asprintf(&s
, "%s %u %u %u %s",
953 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
957 r
= asprintf(&s
, "%s %u %u %s",
966 case DNS_TYPE_DNSKEY
: {
967 _cleanup_free_
char *alg
= NULL
;
971 key_tag
= dnssec_keytag(rr
, true);
973 r
= dnssec_algorithm_to_string_alloc(rr
->dnskey
.algorithm
, &alg
);
977 r
= asprintf(&s
, "%s %u %u %s",
985 r
= base64_append(&s
, r
,
986 rr
->dnskey
.key
, rr
->dnskey
.key_size
,
991 r
= asprintf(&ss
, "%s\n"
995 rr
->dnskey
.flags
& DNSKEY_FLAG_SEP
? " SEP" : "",
996 rr
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
? " REVOKE" : "",
997 rr
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
? " ZONE_KEY" : "",
1007 case DNS_TYPE_RRSIG
: {
1008 _cleanup_free_
char *alg
= NULL
;
1009 char expiration
[STRLEN("YYYYMMDDHHmmSS") + 1], inception
[STRLEN("YYYYMMDDHHmmSS") + 1];
1012 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
1014 r
= dnssec_algorithm_to_string_alloc(rr
->rrsig
.algorithm
, &alg
);
1018 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
1022 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
1027 * http://tools.ietf.org/html/rfc3597#section-5 */
1029 r
= asprintf(&s
, "%s %s%.*u %s %u %u %s %s %u %s",
1032 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
1035 rr
->rrsig
.original_ttl
,
1043 r
= base64_append(&s
, r
,
1044 rr
->rrsig
.signature
, rr
->rrsig
.signature_size
,
1053 t
= format_types(rr
->nsec
.types
);
1057 r
= asprintf(&s
, "%s %s %s",
1059 rr
->nsec
.next_domain_name
,
1065 case DNS_TYPE_NSEC3
: {
1066 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
1068 if (rr
->nsec3
.salt_size
> 0) {
1069 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
1074 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
1078 t
= format_types(rr
->nsec3
.types
);
1082 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
1084 rr
->nsec3
.algorithm
,
1086 rr
->nsec3
.iterations
,
1087 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
1096 case DNS_TYPE_TLSA
: {
1097 const char *cert_usage
, *selector
, *matching_type
;
1099 cert_usage
= tlsa_cert_usage_to_string(rr
->tlsa
.cert_usage
);
1100 selector
= tlsa_selector_to_string(rr
->tlsa
.selector
);
1101 matching_type
= tlsa_matching_type_to_string(rr
->tlsa
.matching_type
);
1103 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
1109 " -- Cert. usage: %s\n"
1110 " -- Selector: %s\n"
1111 " -- Matching type: %s",
1113 rr
->tlsa
.cert_usage
,
1115 rr
->tlsa
.matching_type
,
1126 case DNS_TYPE_CAA
: {
1127 _cleanup_free_
char *value
;
1129 value
= octescape(rr
->caa
.value
, rr
->caa
.value_size
);
1133 r
= asprintf(&s
, "%s %u %s \"%s\"%s%s%s%.0u",
1138 rr
->caa
.flags
? "\n -- Flags:" : "",
1139 rr
->caa
.flags
& CAA_FLAG_CRITICAL
? " critical" : "",
1140 rr
->caa
.flags
& ~CAA_FLAG_CRITICAL
? " " : "",
1141 rr
->caa
.flags
& ~CAA_FLAG_CRITICAL
);
1148 case DNS_TYPE_OPENPGPKEY
: {
1149 r
= asprintf(&s
, "%s", k
);
1153 r
= base64_append(&s
, r
,
1154 rr
->generic
.data
, rr
->generic
.data_size
,
1162 t
= hexmem(rr
->generic
.data
, rr
->generic
.data_size
);
1166 /* Format as documented in RFC 3597, Section 5 */
1167 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.data_size
, t
);
1177 ssize_t
dns_resource_record_payload(DnsResourceRecord
*rr
, void **out
) {
1181 switch(rr
->unparsable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
1185 case DNS_TYPE_CNAME
:
1186 case DNS_TYPE_DNAME
:
1187 case DNS_TYPE_HINFO
:
1196 case DNS_TYPE_DNSKEY
:
1197 case DNS_TYPE_RRSIG
:
1199 case DNS_TYPE_NSEC3
:
1202 case DNS_TYPE_SSHFP
:
1203 *out
= rr
->sshfp
.fingerprint
;
1204 return rr
->sshfp
.fingerprint_size
;
1207 *out
= rr
->tlsa
.data
;
1208 return rr
->tlsa
.data_size
;
1210 case DNS_TYPE_OPENPGPKEY
:
1212 *out
= rr
->generic
.data
;
1213 return rr
->generic
.data_size
;
1217 int dns_resource_record_to_wire_format(DnsResourceRecord
*rr
, bool canonical
) {
1219 DnsPacket packet
= {
1221 .protocol
= DNS_PROTOCOL_DNS
,
1223 .refuse_compression
= true,
1224 .canonical_form
= canonical
,
1232 /* Generates the RR in wire-format, optionally in the
1233 * canonical form as discussed in the DNSSEC RFC 4034, Section
1234 * 6.2. We allocate a throw-away DnsPacket object on the stack
1235 * here, because we need some book-keeping for memory
1236 * management, and can reuse the DnsPacket serializer, that
1237 * can generate the canonical form, too, but also knows label
1238 * compression and suchlike. */
1240 if (rr
->wire_format
&& rr
->wire_format_canonical
== canonical
)
1243 r
= dns_packet_append_rr(&packet
, rr
, 0, &start
, &rds
);
1248 assert(packet
._data
);
1250 free(rr
->wire_format
);
1251 rr
->wire_format
= packet
._data
;
1252 rr
->wire_format_size
= packet
.size
;
1253 rr
->wire_format_rdata_offset
= rds
;
1254 rr
->wire_format_canonical
= canonical
;
1256 packet
._data
= NULL
;
1257 dns_packet_unref(&packet
);
1262 int dns_resource_record_signer(DnsResourceRecord
*rr
, const char **ret
) {
1269 /* Returns the RRset's signer, if it is known. */
1271 if (rr
->n_skip_labels_signer
== UINT_MAX
)
1274 n
= dns_resource_key_name(rr
->key
);
1275 r
= dns_name_skip(n
, rr
->n_skip_labels_signer
, &n
);
1285 int dns_resource_record_source(DnsResourceRecord
*rr
, const char **ret
) {
1292 /* Returns the RRset's synthesizing source, if it is known. */
1294 if (rr
->n_skip_labels_source
== UINT_MAX
)
1297 n
= dns_resource_key_name(rr
->key
);
1298 r
= dns_name_skip(n
, rr
->n_skip_labels_source
, &n
);
1308 int dns_resource_record_is_signer(DnsResourceRecord
*rr
, const char *zone
) {
1314 r
= dns_resource_record_signer(rr
, &signer
);
1318 return dns_name_equal(zone
, signer
);
1321 int dns_resource_record_is_synthetic(DnsResourceRecord
*rr
) {
1326 /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */
1328 if (rr
->n_skip_labels_source
== UINT_MAX
)
1331 if (rr
->n_skip_labels_source
== 0)
1334 if (rr
->n_skip_labels_source
> 1)
1337 r
= dns_name_startswith(dns_resource_key_name(rr
->key
), "*");
1344 void dns_resource_record_hash_func(const DnsResourceRecord
*rr
, struct siphash
*state
) {
1347 dns_resource_key_hash_func(rr
->key
, state
);
1349 switch (rr
->unparsable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
1352 siphash24_compress(&rr
->srv
.priority
, sizeof(rr
->srv
.priority
), state
);
1353 siphash24_compress(&rr
->srv
.weight
, sizeof(rr
->srv
.weight
), state
);
1354 siphash24_compress(&rr
->srv
.port
, sizeof(rr
->srv
.port
), state
);
1355 dns_name_hash_func(rr
->srv
.name
, state
);
1360 case DNS_TYPE_CNAME
:
1361 case DNS_TYPE_DNAME
:
1362 dns_name_hash_func(rr
->ptr
.name
, state
);
1365 case DNS_TYPE_HINFO
:
1366 string_hash_func(rr
->hinfo
.cpu
, state
);
1367 string_hash_func(rr
->hinfo
.os
, state
);
1371 case DNS_TYPE_SPF
: {
1374 LIST_FOREACH(items
, j
, rr
->txt
.items
) {
1375 siphash24_compress_safe(j
->data
, j
->length
, state
);
1377 /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab"
1378 * followed by "". */
1379 siphash24_compress_byte(0, state
);
1385 siphash24_compress(&rr
->a
.in_addr
, sizeof(rr
->a
.in_addr
), state
);
1389 siphash24_compress(&rr
->aaaa
.in6_addr
, sizeof(rr
->aaaa
.in6_addr
), state
);
1393 dns_name_hash_func(rr
->soa
.mname
, state
);
1394 dns_name_hash_func(rr
->soa
.rname
, state
);
1395 siphash24_compress(&rr
->soa
.serial
, sizeof(rr
->soa
.serial
), state
);
1396 siphash24_compress(&rr
->soa
.refresh
, sizeof(rr
->soa
.refresh
), state
);
1397 siphash24_compress(&rr
->soa
.retry
, sizeof(rr
->soa
.retry
), state
);
1398 siphash24_compress(&rr
->soa
.expire
, sizeof(rr
->soa
.expire
), state
);
1399 siphash24_compress(&rr
->soa
.minimum
, sizeof(rr
->soa
.minimum
), state
);
1403 siphash24_compress(&rr
->mx
.priority
, sizeof(rr
->mx
.priority
), state
);
1404 dns_name_hash_func(rr
->mx
.exchange
, state
);
1408 siphash24_compress(&rr
->loc
.version
, sizeof(rr
->loc
.version
), state
);
1409 siphash24_compress(&rr
->loc
.size
, sizeof(rr
->loc
.size
), state
);
1410 siphash24_compress(&rr
->loc
.horiz_pre
, sizeof(rr
->loc
.horiz_pre
), state
);
1411 siphash24_compress(&rr
->loc
.vert_pre
, sizeof(rr
->loc
.vert_pre
), state
);
1412 siphash24_compress(&rr
->loc
.latitude
, sizeof(rr
->loc
.latitude
), state
);
1413 siphash24_compress(&rr
->loc
.longitude
, sizeof(rr
->loc
.longitude
), state
);
1414 siphash24_compress(&rr
->loc
.altitude
, sizeof(rr
->loc
.altitude
), state
);
1417 case DNS_TYPE_SSHFP
:
1418 siphash24_compress(&rr
->sshfp
.algorithm
, sizeof(rr
->sshfp
.algorithm
), state
);
1419 siphash24_compress(&rr
->sshfp
.fptype
, sizeof(rr
->sshfp
.fptype
), state
);
1420 siphash24_compress_safe(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
, state
);
1423 case DNS_TYPE_DNSKEY
:
1424 siphash24_compress(&rr
->dnskey
.flags
, sizeof(rr
->dnskey
.flags
), state
);
1425 siphash24_compress(&rr
->dnskey
.protocol
, sizeof(rr
->dnskey
.protocol
), state
);
1426 siphash24_compress(&rr
->dnskey
.algorithm
, sizeof(rr
->dnskey
.algorithm
), state
);
1427 siphash24_compress_safe(rr
->dnskey
.key
, rr
->dnskey
.key_size
, state
);
1430 case DNS_TYPE_RRSIG
:
1431 siphash24_compress(&rr
->rrsig
.type_covered
, sizeof(rr
->rrsig
.type_covered
), state
);
1432 siphash24_compress(&rr
->rrsig
.algorithm
, sizeof(rr
->rrsig
.algorithm
), state
);
1433 siphash24_compress(&rr
->rrsig
.labels
, sizeof(rr
->rrsig
.labels
), state
);
1434 siphash24_compress(&rr
->rrsig
.original_ttl
, sizeof(rr
->rrsig
.original_ttl
), state
);
1435 siphash24_compress(&rr
->rrsig
.expiration
, sizeof(rr
->rrsig
.expiration
), state
);
1436 siphash24_compress(&rr
->rrsig
.inception
, sizeof(rr
->rrsig
.inception
), state
);
1437 siphash24_compress(&rr
->rrsig
.key_tag
, sizeof(rr
->rrsig
.key_tag
), state
);
1438 dns_name_hash_func(rr
->rrsig
.signer
, state
);
1439 siphash24_compress_safe(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
, state
);
1443 dns_name_hash_func(rr
->nsec
.next_domain_name
, state
);
1444 /* FIXME: we leave out the type bitmap here. Hash
1445 * would be better if we'd take it into account
1450 siphash24_compress(&rr
->ds
.key_tag
, sizeof(rr
->ds
.key_tag
), state
);
1451 siphash24_compress(&rr
->ds
.algorithm
, sizeof(rr
->ds
.algorithm
), state
);
1452 siphash24_compress(&rr
->ds
.digest_type
, sizeof(rr
->ds
.digest_type
), state
);
1453 siphash24_compress_safe(rr
->ds
.digest
, rr
->ds
.digest_size
, state
);
1456 case DNS_TYPE_NSEC3
:
1457 siphash24_compress(&rr
->nsec3
.algorithm
, sizeof(rr
->nsec3
.algorithm
), state
);
1458 siphash24_compress(&rr
->nsec3
.flags
, sizeof(rr
->nsec3
.flags
), state
);
1459 siphash24_compress(&rr
->nsec3
.iterations
, sizeof(rr
->nsec3
.iterations
), state
);
1460 siphash24_compress_safe(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
, state
);
1461 siphash24_compress_safe(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, state
);
1462 /* FIXME: We leave the bitmaps out */
1466 siphash24_compress(&rr
->tlsa
.cert_usage
, sizeof(rr
->tlsa
.cert_usage
), state
);
1467 siphash24_compress(&rr
->tlsa
.selector
, sizeof(rr
->tlsa
.selector
), state
);
1468 siphash24_compress(&rr
->tlsa
.matching_type
, sizeof(rr
->tlsa
.matching_type
), state
);
1469 siphash24_compress_safe(rr
->tlsa
.data
, rr
->tlsa
.data_size
, state
);
1473 siphash24_compress(&rr
->caa
.flags
, sizeof(rr
->caa
.flags
), state
);
1474 string_hash_func(rr
->caa
.tag
, state
);
1475 siphash24_compress_safe(rr
->caa
.value
, rr
->caa
.value_size
, state
);
1478 case DNS_TYPE_OPENPGPKEY
:
1480 siphash24_compress_safe(rr
->generic
.data
, rr
->generic
.data_size
, state
);
1485 int dns_resource_record_compare_func(const DnsResourceRecord
*x
, const DnsResourceRecord
*y
) {
1488 r
= dns_resource_key_compare_func(x
->key
, y
->key
);
1492 if (dns_resource_record_payload_equal(x
, y
) > 0)
1495 /* We still use CMP() here, even though don't implement proper
1496 * ordering, since the hashtable doesn't need ordering anyway. */
1500 DEFINE_HASH_OPS(dns_resource_record_hash_ops
, DnsResourceRecord
, dns_resource_record_hash_func
, dns_resource_record_compare_func
);
1502 DnsResourceRecord
*dns_resource_record_copy(DnsResourceRecord
*rr
) {
1503 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*copy
= NULL
;
1504 DnsResourceRecord
*t
;
1508 copy
= dns_resource_record_new(rr
->key
);
1512 copy
->ttl
= rr
->ttl
;
1513 copy
->expiry
= rr
->expiry
;
1514 copy
->n_skip_labels_signer
= rr
->n_skip_labels_signer
;
1515 copy
->n_skip_labels_source
= rr
->n_skip_labels_source
;
1516 copy
->unparsable
= rr
->unparsable
;
1518 switch (rr
->unparsable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
1521 copy
->srv
.priority
= rr
->srv
.priority
;
1522 copy
->srv
.weight
= rr
->srv
.weight
;
1523 copy
->srv
.port
= rr
->srv
.port
;
1524 copy
->srv
.name
= strdup(rr
->srv
.name
);
1525 if (!copy
->srv
.name
)
1531 case DNS_TYPE_CNAME
:
1532 case DNS_TYPE_DNAME
:
1533 copy
->ptr
.name
= strdup(rr
->ptr
.name
);
1534 if (!copy
->ptr
.name
)
1538 case DNS_TYPE_HINFO
:
1539 copy
->hinfo
.cpu
= strdup(rr
->hinfo
.cpu
);
1540 if (!copy
->hinfo
.cpu
)
1543 copy
->hinfo
.os
= strdup(rr
->hinfo
.os
);
1544 if (!copy
->hinfo
.os
)
1550 copy
->txt
.items
= dns_txt_item_copy(rr
->txt
.items
);
1551 if (!copy
->txt
.items
)
1560 copy
->aaaa
= rr
->aaaa
;
1564 copy
->soa
.mname
= strdup(rr
->soa
.mname
);
1565 if (!copy
->soa
.mname
)
1567 copy
->soa
.rname
= strdup(rr
->soa
.rname
);
1568 if (!copy
->soa
.rname
)
1570 copy
->soa
.serial
= rr
->soa
.serial
;
1571 copy
->soa
.refresh
= rr
->soa
.refresh
;
1572 copy
->soa
.retry
= rr
->soa
.retry
;
1573 copy
->soa
.expire
= rr
->soa
.expire
;
1574 copy
->soa
.minimum
= rr
->soa
.minimum
;
1578 copy
->mx
.priority
= rr
->mx
.priority
;
1579 copy
->mx
.exchange
= strdup(rr
->mx
.exchange
);
1580 if (!copy
->mx
.exchange
)
1585 copy
->loc
= rr
->loc
;
1588 case DNS_TYPE_SSHFP
:
1589 copy
->sshfp
.algorithm
= rr
->sshfp
.algorithm
;
1590 copy
->sshfp
.fptype
= rr
->sshfp
.fptype
;
1591 copy
->sshfp
.fingerprint
= memdup(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
1592 if (!copy
->sshfp
.fingerprint
)
1594 copy
->sshfp
.fingerprint_size
= rr
->sshfp
.fingerprint_size
;
1597 case DNS_TYPE_DNSKEY
:
1598 copy
->dnskey
.flags
= rr
->dnskey
.flags
;
1599 copy
->dnskey
.protocol
= rr
->dnskey
.protocol
;
1600 copy
->dnskey
.algorithm
= rr
->dnskey
.algorithm
;
1601 copy
->dnskey
.key
= memdup(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
1602 if (!copy
->dnskey
.key
)
1604 copy
->dnskey
.key_size
= rr
->dnskey
.key_size
;
1607 case DNS_TYPE_RRSIG
:
1608 copy
->rrsig
.type_covered
= rr
->rrsig
.type_covered
;
1609 copy
->rrsig
.algorithm
= rr
->rrsig
.algorithm
;
1610 copy
->rrsig
.labels
= rr
->rrsig
.labels
;
1611 copy
->rrsig
.original_ttl
= rr
->rrsig
.original_ttl
;
1612 copy
->rrsig
.expiration
= rr
->rrsig
.expiration
;
1613 copy
->rrsig
.inception
= rr
->rrsig
.inception
;
1614 copy
->rrsig
.key_tag
= rr
->rrsig
.key_tag
;
1615 copy
->rrsig
.signer
= strdup(rr
->rrsig
.signer
);
1616 if (!copy
->rrsig
.signer
)
1618 copy
->rrsig
.signature
= memdup(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
1619 if (!copy
->rrsig
.signature
)
1621 copy
->rrsig
.signature_size
= rr
->rrsig
.signature_size
;
1625 copy
->nsec
.next_domain_name
= strdup(rr
->nsec
.next_domain_name
);
1626 if (!copy
->nsec
.next_domain_name
)
1628 copy
->nsec
.types
= bitmap_copy(rr
->nsec
.types
);
1629 if (!copy
->nsec
.types
)
1634 copy
->ds
.key_tag
= rr
->ds
.key_tag
;
1635 copy
->ds
.algorithm
= rr
->ds
.algorithm
;
1636 copy
->ds
.digest_type
= rr
->ds
.digest_type
;
1637 copy
->ds
.digest
= memdup(rr
->ds
.digest
, rr
->ds
.digest_size
);
1638 if (!copy
->ds
.digest
)
1640 copy
->ds
.digest_size
= rr
->ds
.digest_size
;
1643 case DNS_TYPE_NSEC3
:
1644 copy
->nsec3
.algorithm
= rr
->nsec3
.algorithm
;
1645 copy
->nsec3
.flags
= rr
->nsec3
.flags
;
1646 copy
->nsec3
.iterations
= rr
->nsec3
.iterations
;
1647 copy
->nsec3
.salt
= memdup(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
1648 if (!copy
->nsec3
.salt
)
1650 copy
->nsec3
.salt_size
= rr
->nsec3
.salt_size
;
1651 copy
->nsec3
.next_hashed_name
= memdup(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
);
1652 if (!copy
->nsec3
.next_hashed_name
)
1654 copy
->nsec3
.next_hashed_name_size
= rr
->nsec3
.next_hashed_name_size
;
1655 copy
->nsec3
.types
= bitmap_copy(rr
->nsec3
.types
);
1656 if (!copy
->nsec3
.types
)
1661 copy
->tlsa
.cert_usage
= rr
->tlsa
.cert_usage
;
1662 copy
->tlsa
.selector
= rr
->tlsa
.selector
;
1663 copy
->tlsa
.matching_type
= rr
->tlsa
.matching_type
;
1664 copy
->tlsa
.data
= memdup(rr
->tlsa
.data
, rr
->tlsa
.data_size
);
1665 if (!copy
->tlsa
.data
)
1667 copy
->tlsa
.data_size
= rr
->tlsa
.data_size
;
1671 copy
->caa
.flags
= rr
->caa
.flags
;
1672 copy
->caa
.tag
= strdup(rr
->caa
.tag
);
1675 copy
->caa
.value
= memdup(rr
->caa
.value
, rr
->caa
.value_size
);
1676 if (!copy
->caa
.value
)
1678 copy
->caa
.value_size
= rr
->caa
.value_size
;
1683 copy
->generic
.data
= memdup(rr
->generic
.data
, rr
->generic
.data_size
);
1684 if (!copy
->generic
.data
)
1686 copy
->generic
.data_size
= rr
->generic
.data_size
;
1695 int dns_resource_record_clamp_ttl(DnsResourceRecord
**rr
, uint32_t max_ttl
) {
1696 DnsResourceRecord
*old_rr
, *new_rr
;
1702 if (old_rr
->key
->type
== DNS_TYPE_OPT
)
1705 new_ttl
= MIN(old_rr
->ttl
, max_ttl
);
1706 if (new_ttl
== old_rr
->ttl
)
1709 if (old_rr
->n_ref
== 1) {
1710 /* Patch in place */
1711 old_rr
->ttl
= new_ttl
;
1715 new_rr
= dns_resource_record_copy(old_rr
);
1719 new_rr
->ttl
= new_ttl
;
1721 dns_resource_record_unref(*rr
);
1727 bool dns_resource_record_is_link_local_address(DnsResourceRecord
*rr
) {
1730 if (rr
->key
->class != DNS_CLASS_IN
)
1733 if (rr
->key
->type
== DNS_TYPE_A
)
1734 return in4_addr_is_link_local(&rr
->a
.in_addr
);
1736 if (rr
->key
->type
== DNS_TYPE_AAAA
)
1737 return in6_addr_is_link_local(&rr
->aaaa
.in6_addr
);
1742 int dns_resource_record_get_cname_target(DnsResourceKey
*key
, DnsResourceRecord
*cname
, char **ret
) {
1743 _cleanup_free_
char *d
= NULL
;
1749 /* Checks if the RR `cname` is a CNAME/DNAME RR that matches the specified `key`. If so, returns the
1750 * target domain. If not, returns -EUNATCH */
1752 if (key
->class != cname
->key
->class && key
->class != DNS_CLASS_ANY
)
1755 if (!dns_type_may_redirect(key
->type
)) /* This key type is not subject to CNAME/DNAME redirection?
1756 * Then let's refuse right-away */
1759 if (cname
->key
->type
== DNS_TYPE_CNAME
) {
1760 r
= dns_name_equal(dns_resource_key_name(key
),
1761 dns_resource_key_name(cname
->key
));
1765 return -EUNATCH
; /* CNAME RR key doesn't actually match the original key */
1767 d
= strdup(cname
->cname
.name
);
1771 } else if (cname
->key
->type
== DNS_TYPE_DNAME
) {
1773 r
= dns_name_change_suffix(
1774 dns_resource_key_name(key
),
1775 dns_resource_key_name(cname
->key
),
1781 return -EUNATCH
; /* DNAME RR key doesn't actually match the original key */
1784 return -EUNATCH
; /* Not a CNAME/DNAME RR, hence doesn't match the proposition either */
1790 DnsTxtItem
*dns_txt_item_free_all(DnsTxtItem
*i
) {
1799 return dns_txt_item_free_all(n
);
1802 bool dns_txt_item_equal(DnsTxtItem
*a
, DnsTxtItem
*b
) {
1813 if (a
->length
!= b
->length
)
1816 if (memcmp(a
->data
, b
->data
, a
->length
) != 0)
1819 return dns_txt_item_equal(a
->items_next
, b
->items_next
);
1822 DnsTxtItem
*dns_txt_item_copy(DnsTxtItem
*first
) {
1823 DnsTxtItem
*i
, *copy
= NULL
, *end
= NULL
;
1825 LIST_FOREACH(items
, i
, first
) {
1828 j
= memdup(i
, offsetof(DnsTxtItem
, data
) + i
->length
+ 1);
1830 dns_txt_item_free_all(copy
);
1834 LIST_INSERT_AFTER(items
, copy
, end
, j
);
1841 int dns_txt_item_new_empty(DnsTxtItem
**ret
) {
1844 /* RFC 6763, section 6.1 suggests to treat
1845 * empty TXT RRs as equivalent to a TXT record
1846 * with a single empty string. */
1848 i
= malloc0(offsetof(DnsTxtItem
, data
) + 1); /* for safety reasons we add an extra NUL byte */
1857 static const char* const dnssec_algorithm_table
[_DNSSEC_ALGORITHM_MAX_DEFINED
] = {
1858 /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
1859 [DNSSEC_ALGORITHM_RSAMD5
] = "RSAMD5",
1860 [DNSSEC_ALGORITHM_DH
] = "DH",
1861 [DNSSEC_ALGORITHM_DSA
] = "DSA",
1862 [DNSSEC_ALGORITHM_ECC
] = "ECC",
1863 [DNSSEC_ALGORITHM_RSASHA1
] = "RSASHA1",
1864 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1
] = "DSA-NSEC3-SHA1",
1865 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
] = "RSASHA1-NSEC3-SHA1",
1866 [DNSSEC_ALGORITHM_RSASHA256
] = "RSASHA256",
1867 [DNSSEC_ALGORITHM_RSASHA512
] = "RSASHA512",
1868 [DNSSEC_ALGORITHM_ECC_GOST
] = "ECC-GOST",
1869 [DNSSEC_ALGORITHM_ECDSAP256SHA256
] = "ECDSAP256SHA256",
1870 [DNSSEC_ALGORITHM_ECDSAP384SHA384
] = "ECDSAP384SHA384",
1871 [DNSSEC_ALGORITHM_ED25519
] = "ED25519",
1872 [DNSSEC_ALGORITHM_ED448
] = "ED448",
1873 [DNSSEC_ALGORITHM_INDIRECT
] = "INDIRECT",
1874 [DNSSEC_ALGORITHM_PRIVATEDNS
] = "PRIVATEDNS",
1875 [DNSSEC_ALGORITHM_PRIVATEOID
] = "PRIVATEOID",
1877 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm
, int, 255);
1879 static const char* const dnssec_digest_table
[_DNSSEC_DIGEST_MAX_DEFINED
] = {
1880 /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
1881 [DNSSEC_DIGEST_SHA1
] = "SHA-1",
1882 [DNSSEC_DIGEST_SHA256
] = "SHA-256",
1883 [DNSSEC_DIGEST_GOST_R_34_11_94
] = "GOST_R_34.11-94",
1884 [DNSSEC_DIGEST_SHA384
] = "SHA-384",
1886 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest
, int, 255);