1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
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.
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.
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/>.
24 #include "alloc-util.h"
25 #include "dns-domain.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"
34 DnsResourceKey
* dns_resource_key_new(uint16_t class, uint16_t type
, const char *name
) {
41 k
= malloc0(sizeof(DnsResourceKey
) + l
+ 1);
49 strcpy((char*) k
+ sizeof(DnsResourceKey
), name
);
54 DnsResourceKey
* dns_resource_key_new_redirect(const DnsResourceKey
*key
, const DnsResourceRecord
*cname
) {
60 assert(IN_SET(cname
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
));
62 if (cname
->key
->type
== DNS_TYPE_CNAME
)
63 return dns_resource_key_new(key
->class, key
->type
, cname
->cname
.name
);
66 char *destination
= NULL
;
68 r
= dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(cname
->key
), cname
->dname
.name
, &destination
);
72 return dns_resource_key_ref((DnsResourceKey
*) key
);
74 k
= dns_resource_key_new_consume(key
->class, key
->type
, 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 bool dns_resource_key_is_address(const DnsResourceKey
*key
) {
163 /* Check if this is an A or AAAA resource key */
165 return key
->class == DNS_CLASS_IN
&& IN_SET(key
->type
, DNS_TYPE_A
, DNS_TYPE_AAAA
);
168 int dns_resource_key_equal(const DnsResourceKey
*a
, const DnsResourceKey
*b
) {
174 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(a
), DNS_RESOURCE_KEY_NAME(b
));
178 if (a
->class != b
->class)
181 if (a
->type
!= b
->type
)
187 int dns_resource_key_match_rr(const DnsResourceKey
*key
, DnsResourceRecord
*rr
, const char *search_domain
) {
196 /* Checks if an rr matches the specified key. If a search
197 * domain is specified, it will also be checked if the key
198 * with the search domain suffixed might match the RR. */
200 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
203 if (rr
->key
->type
!= key
->type
&& key
->type
!= DNS_TYPE_ANY
)
206 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
211 _cleanup_free_
char *joined
= NULL
;
213 r
= dns_name_concat(DNS_RESOURCE_KEY_NAME(key
), search_domain
, &joined
);
217 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), joined
);
223 int dns_resource_key_match_cname_or_dname(const DnsResourceKey
*key
, const DnsResourceKey
*cname
, const char *search_domain
) {
229 if (cname
->class != key
->class && key
->class != DNS_CLASS_ANY
)
232 if (cname
->type
== DNS_TYPE_CNAME
)
233 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(cname
));
234 else if (cname
->type
== DNS_TYPE_DNAME
)
235 r
= dns_name_endswith(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(cname
));
243 _cleanup_free_
char *joined
= NULL
;
245 r
= dns_name_concat(DNS_RESOURCE_KEY_NAME(key
), search_domain
, &joined
);
249 if (cname
->type
== DNS_TYPE_CNAME
)
250 return dns_name_equal(joined
, DNS_RESOURCE_KEY_NAME(cname
));
251 else if (cname
->type
== DNS_TYPE_DNAME
)
252 return dns_name_endswith(joined
, DNS_RESOURCE_KEY_NAME(cname
));
258 int dns_resource_key_match_soa(const DnsResourceKey
*key
, const DnsResourceKey
*soa
) {
262 /* Checks whether 'soa' is a SOA record for the specified key. */
264 if (soa
->class != key
->class)
267 if (soa
->type
!= DNS_TYPE_SOA
)
270 return dns_name_endswith(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(soa
));
273 static void dns_resource_key_hash_func(const void *i
, struct siphash
*state
) {
274 const DnsResourceKey
*k
= i
;
278 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k
), state
);
279 siphash24_compress(&k
->class, sizeof(k
->class), state
);
280 siphash24_compress(&k
->type
, sizeof(k
->type
), state
);
283 static int dns_resource_key_compare_func(const void *a
, const void *b
) {
284 const DnsResourceKey
*x
= a
, *y
= b
;
287 ret
= dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x
), DNS_RESOURCE_KEY_NAME(y
));
291 if (x
->type
< y
->type
)
293 if (x
->type
> y
->type
)
296 if (x
->class < y
->class)
298 if (x
->class > y
->class)
304 const struct hash_ops dns_resource_key_hash_ops
= {
305 .hash
= dns_resource_key_hash_func
,
306 .compare
= dns_resource_key_compare_func
309 int dns_resource_key_to_string(const DnsResourceKey
*key
, char **ret
) {
310 char cbuf
[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf
[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
314 c
= dns_class_to_string(key
->class);
316 sprintf(cbuf
, "CLASS%u", key
->class);
320 t
= dns_type_to_string(key
->type
);
322 sprintf(tbuf
, "TYPE%u", key
->type
);
326 if (asprintf(&s
, "%s. %s %-5s", DNS_RESOURCE_KEY_NAME(key
), c
, t
) < 0)
333 DnsResourceRecord
* dns_resource_record_new(DnsResourceKey
*key
) {
334 DnsResourceRecord
*rr
;
336 rr
= new0(DnsResourceRecord
, 1);
341 rr
->key
= dns_resource_key_ref(key
);
346 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
347 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
349 key
= dns_resource_key_new(class, type
, name
);
353 return dns_resource_record_new(key
);
356 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
360 assert(rr
->n_ref
> 0);
366 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
370 assert(rr
->n_ref
> 0);
378 switch(rr
->key
->type
) {
398 dns_txt_item_free_all(rr
->txt
.items
);
407 free(rr
->mx
.exchange
);
415 free(rr
->sshfp
.fingerprint
);
418 case DNS_TYPE_DNSKEY
:
419 free(rr
->dnskey
.key
);
423 free(rr
->rrsig
.signer
);
424 free(rr
->rrsig
.signature
);
428 free(rr
->nsec
.next_domain_name
);
429 bitmap_free(rr
->nsec
.types
);
433 free(rr
->nsec3
.next_hashed_name
);
434 free(rr
->nsec3
.salt
);
435 bitmap_free(rr
->nsec3
.types
);
444 free(rr
->generic
.data
);
447 free(rr
->wire_format
);
448 dns_resource_key_unref(rr
->key
);
456 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
457 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
458 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
459 _cleanup_free_
char *ptr
= NULL
;
466 r
= dns_name_reverse(family
, address
, &ptr
);
470 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
476 rr
= dns_resource_record_new(key
);
480 rr
->ptr
.name
= strdup(hostname
);
490 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
491 DnsResourceRecord
*rr
;
497 if (family
== AF_INET
) {
499 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
503 rr
->a
.in_addr
= address
->in
;
505 } else if (family
== AF_INET6
) {
507 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
511 rr
->aaaa
.in6_addr
= address
->in6
;
513 return -EAFNOSUPPORT
;
520 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
529 r
= dns_resource_key_equal(a
->key
, b
->key
);
533 if (a
->unparseable
!= b
->unparseable
)
536 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
539 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
543 return a
->srv
.priority
== b
->srv
.priority
&&
544 a
->srv
.weight
== b
->srv
.weight
&&
545 a
->srv
.port
== b
->srv
.port
;
551 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
554 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
555 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
557 case DNS_TYPE_SPF
: /* exactly the same as TXT */
559 return dns_txt_item_equal(a
->txt
.items
, b
->txt
.items
);
562 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
565 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
568 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
571 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
575 return a
->soa
.serial
== b
->soa
.serial
&&
576 a
->soa
.refresh
== b
->soa
.refresh
&&
577 a
->soa
.retry
== b
->soa
.retry
&&
578 a
->soa
.expire
== b
->soa
.expire
&&
579 a
->soa
.minimum
== b
->soa
.minimum
;
582 if (a
->mx
.priority
!= b
->mx
.priority
)
585 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
588 assert(a
->loc
.version
== b
->loc
.version
);
590 return a
->loc
.size
== b
->loc
.size
&&
591 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
592 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
593 a
->loc
.latitude
== b
->loc
.latitude
&&
594 a
->loc
.longitude
== b
->loc
.longitude
&&
595 a
->loc
.altitude
== b
->loc
.altitude
;
598 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
599 a
->ds
.algorithm
== b
->ds
.algorithm
&&
600 a
->ds
.digest_type
== b
->ds
.digest_type
&&
601 a
->ds
.digest_size
== b
->ds
.digest_size
&&
602 memcmp(a
->ds
.digest
, b
->ds
.digest
, a
->ds
.digest_size
) == 0;
605 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
606 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
607 a
->sshfp
.fingerprint_size
== b
->sshfp
.fingerprint_size
&&
608 memcmp(a
->sshfp
.fingerprint
, b
->sshfp
.fingerprint
, a
->sshfp
.fingerprint_size
) == 0;
610 case DNS_TYPE_DNSKEY
:
611 return a
->dnskey
.flags
== b
->dnskey
.flags
&&
612 a
->dnskey
.protocol
== b
->dnskey
.protocol
&&
613 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
614 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
615 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
618 /* do the fast comparisons first */
619 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
620 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
621 a
->rrsig
.labels
!= b
->rrsig
.labels
||
622 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
623 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
624 a
->rrsig
.inception
!= b
->rrsig
.inception
||
625 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
626 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
627 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
630 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
633 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
634 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
637 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
638 a
->nsec3
.flags
== b
->nsec3
.flags
&&
639 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
640 a
->nsec3
.salt_size
== b
->nsec3
.salt_size
&&
641 memcmp(a
->nsec3
.salt
, b
->nsec3
.salt
, a
->nsec3
.salt_size
) == 0 &&
642 memcmp(a
->nsec3
.next_hashed_name
, b
->nsec3
.next_hashed_name
, a
->nsec3
.next_hashed_name_size
) == 0 &&
643 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
646 return a
->generic
.size
== b
->generic
.size
&&
647 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
651 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
652 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
654 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
655 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
657 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
658 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
659 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
660 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
661 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
662 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
664 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
667 (lat
% 60000) / 1000.,
671 (lon
% 60000) / 1000.,
682 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
686 assert(l
> strlen("YYYYMMDDHHmmSS"));
688 if (!gmtime_r(&sec
, &tm
))
691 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
697 static char *format_types(Bitmap
*types
) {
698 _cleanup_strv_free_
char **strv
= NULL
;
699 _cleanup_free_
char *str
= NULL
;
704 BITMAP_FOREACH(type
, types
, i
) {
705 if (dns_type_to_string(type
)) {
706 r
= strv_extend(&strv
, dns_type_to_string(type
));
712 r
= asprintf(&t
, "TYPE%u", type
);
716 r
= strv_consume(&strv
, t
);
722 str
= strv_join(strv
, " ");
726 return strjoin("( ", str
, " )", NULL
);
729 static char *format_txt(DnsTxtItem
*first
) {
734 LIST_FOREACH(items
, i
, first
)
735 c
+= i
->length
* 4 + 3;
737 p
= s
= new(char, c
);
741 LIST_FOREACH(items
, i
, first
) {
749 for (j
= 0; j
< i
->length
; j
++) {
750 if (i
->data
[j
] < ' ' || i
->data
[j
] == '"' || i
->data
[j
] >= 127) {
752 *(p
++) = '0' + (i
->data
[j
] / 100);
753 *(p
++) = '0' + ((i
->data
[j
] / 10) % 10);
754 *(p
++) = '0' + (i
->data
[j
] % 10);
766 int dns_resource_record_to_string(const DnsResourceRecord
*rr
, char **ret
) {
767 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
773 r
= dns_resource_key_to_string(rr
->key
, &k
);
777 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
780 r
= asprintf(&s
, "%s %u %u %u %s",
785 strna(rr
->srv
.name
));
794 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
801 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
806 case DNS_TYPE_SPF
: /* exactly the same as TXT */
808 t
= format_txt(rr
->txt
.items
);
812 s
= strjoin(k
, " ", t
, NULL
);
818 _cleanup_free_
char *x
= NULL
;
820 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
824 s
= strjoin(k
, " ", x
, NULL
);
831 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
835 s
= strjoin(k
, " ", t
, NULL
);
841 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
843 strna(rr
->soa
.mname
),
844 strna(rr
->soa
.rname
),
855 r
= asprintf(&s
, "%s %u %s",
864 assert(rr
->loc
.version
== 0);
866 t
= format_location(rr
->loc
.latitude
,
875 s
= strjoin(k
, " ", t
, NULL
);
881 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
885 r
= asprintf(&s
, "%s %u %u %u %s",
896 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
900 r
= asprintf(&s
, "%s %u %u %s",
909 case DNS_TYPE_DNSKEY
: {
912 alg
= dnssec_algorithm_to_string(rr
->dnskey
.algorithm
);
914 t
= base64mem(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
918 r
= asprintf(&s
, "%s %u %u %.*s%.*u %s",
923 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->dnskey
.algorithm
,
930 case DNS_TYPE_RRSIG
: {
931 const char *type
, *alg
;
932 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
934 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
935 alg
= dnssec_algorithm_to_string(rr
->rrsig
.algorithm
);
937 t
= base64mem(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
941 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
945 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
950 * http://tools.ietf.org/html/rfc3597#section-5 */
952 r
= asprintf(&s
, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
955 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
957 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->rrsig
.algorithm
,
959 rr
->rrsig
.original_ttl
,
971 t
= format_types(rr
->nsec
.types
);
975 r
= asprintf(&s
, "%s %s %s",
977 rr
->nsec
.next_domain_name
,
983 case DNS_TYPE_NSEC3
: {
984 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
986 if (rr
->nsec3
.salt_size
> 0) {
987 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
992 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
996 t
= format_types(rr
->nsec3
.types
);
1000 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
1002 rr
->nsec3
.algorithm
,
1004 rr
->nsec3
.iterations
,
1005 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
1015 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
1019 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.size
, t
);
1029 int dns_resource_record_to_wire_format(DnsResourceRecord
*rr
, bool canonical
) {
1031 DnsPacket packet
= {
1033 .protocol
= DNS_PROTOCOL_DNS
,
1035 .refuse_compression
= true,
1036 .canonical_form
= canonical
,
1044 /* Generates the RR in wire-format, optionally in the
1045 * canonical form as discussed in the DNSSEC RFC 4034, Section
1046 * 6.2. We allocate a throw-away DnsPacket object on the stack
1047 * here, because we need some book-keeping for memory
1048 * management, and can reuse the DnsPacket serializer, that
1049 * can generate the canonical form, too, but also knows label
1050 * compression and suchlike. */
1052 if (rr
->wire_format
&& rr
->wire_format_canonical
== canonical
)
1055 r
= dns_packet_append_rr(&packet
, rr
, &start
, &rds
);
1060 assert(packet
._data
);
1062 free(rr
->wire_format
);
1063 rr
->wire_format
= packet
._data
;
1064 rr
->wire_format_size
= packet
.size
;
1065 rr
->wire_format_rdata_offset
= rds
;
1066 rr
->wire_format_canonical
= canonical
;
1068 packet
._data
= NULL
;
1069 dns_packet_unref(&packet
);
1074 DnsTxtItem
*dns_txt_item_free_all(DnsTxtItem
*i
) {
1083 return dns_txt_item_free_all(n
);
1086 bool dns_txt_item_equal(DnsTxtItem
*a
, DnsTxtItem
*b
) {
1097 if (a
->length
!= b
->length
)
1100 if (memcmp(a
->data
, b
->data
, a
->length
) != 0)
1103 return dns_txt_item_equal(a
->items_next
, b
->items_next
);
1106 static const char* const dnssec_algorithm_table
[_DNSSEC_ALGORITHM_MAX_DEFINED
] = {
1107 [DNSSEC_ALGORITHM_RSAMD5
] = "RSAMD5",
1108 [DNSSEC_ALGORITHM_DH
] = "DH",
1109 [DNSSEC_ALGORITHM_DSA
] = "DSA",
1110 [DNSSEC_ALGORITHM_ECC
] = "ECC",
1111 [DNSSEC_ALGORITHM_RSASHA1
] = "RSASHA1",
1112 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1
] = "DSA-NSEC3-SHA1",
1113 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
] = "RSASHA1-NSEC3-SHA1",
1114 [DNSSEC_ALGORITHM_RSASHA256
] = "RSASHA256",
1115 [DNSSEC_ALGORITHM_RSASHA512
] = "RSASHA512",
1116 [DNSSEC_ALGORITHM_INDIRECT
] = "INDIRECT",
1117 [DNSSEC_ALGORITHM_PRIVATEDNS
] = "PRIVATEDNS",
1118 [DNSSEC_ALGORITHM_PRIVATEOID
] = "PRIVATEOID",
1120 DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm
, int);
1122 static const char* const dnssec_digest_table
[_DNSSEC_DIGEST_MAX_DEFINED
] = {
1123 [DNSSEC_DIGEST_SHA1
] = "SHA1",
1124 [DNSSEC_DIGEST_SHA256
] = "SHA256",
1126 DEFINE_STRING_TABLE_LOOKUP(dnssec_digest
, int);