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
);
342 rr
->expiry
= USEC_INFINITY
;
347 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
348 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
350 key
= dns_resource_key_new(class, type
, name
);
354 return dns_resource_record_new(key
);
357 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
361 assert(rr
->n_ref
> 0);
367 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
371 assert(rr
->n_ref
> 0);
379 switch(rr
->key
->type
) {
399 dns_txt_item_free_all(rr
->txt
.items
);
408 free(rr
->mx
.exchange
);
416 free(rr
->sshfp
.fingerprint
);
419 case DNS_TYPE_DNSKEY
:
420 free(rr
->dnskey
.key
);
424 free(rr
->rrsig
.signer
);
425 free(rr
->rrsig
.signature
);
429 free(rr
->nsec
.next_domain_name
);
430 bitmap_free(rr
->nsec
.types
);
434 free(rr
->nsec3
.next_hashed_name
);
435 free(rr
->nsec3
.salt
);
436 bitmap_free(rr
->nsec3
.types
);
445 free(rr
->generic
.data
);
448 free(rr
->wire_format
);
449 dns_resource_key_unref(rr
->key
);
458 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
459 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
460 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
461 _cleanup_free_
char *ptr
= NULL
;
468 r
= dns_name_reverse(family
, address
, &ptr
);
472 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
478 rr
= dns_resource_record_new(key
);
482 rr
->ptr
.name
= strdup(hostname
);
492 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
493 DnsResourceRecord
*rr
;
499 if (family
== AF_INET
) {
501 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
505 rr
->a
.in_addr
= address
->in
;
507 } else if (family
== AF_INET6
) {
509 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
513 rr
->aaaa
.in6_addr
= address
->in6
;
515 return -EAFNOSUPPORT
;
522 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
531 r
= dns_resource_key_equal(a
->key
, b
->key
);
535 if (a
->unparseable
!= b
->unparseable
)
538 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
541 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
545 return a
->srv
.priority
== b
->srv
.priority
&&
546 a
->srv
.weight
== b
->srv
.weight
&&
547 a
->srv
.port
== b
->srv
.port
;
553 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
556 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
557 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
559 case DNS_TYPE_SPF
: /* exactly the same as TXT */
561 return dns_txt_item_equal(a
->txt
.items
, b
->txt
.items
);
564 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
567 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
570 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
573 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
577 return a
->soa
.serial
== b
->soa
.serial
&&
578 a
->soa
.refresh
== b
->soa
.refresh
&&
579 a
->soa
.retry
== b
->soa
.retry
&&
580 a
->soa
.expire
== b
->soa
.expire
&&
581 a
->soa
.minimum
== b
->soa
.minimum
;
584 if (a
->mx
.priority
!= b
->mx
.priority
)
587 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
590 assert(a
->loc
.version
== b
->loc
.version
);
592 return a
->loc
.size
== b
->loc
.size
&&
593 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
594 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
595 a
->loc
.latitude
== b
->loc
.latitude
&&
596 a
->loc
.longitude
== b
->loc
.longitude
&&
597 a
->loc
.altitude
== b
->loc
.altitude
;
600 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
601 a
->ds
.algorithm
== b
->ds
.algorithm
&&
602 a
->ds
.digest_type
== b
->ds
.digest_type
&&
603 a
->ds
.digest_size
== b
->ds
.digest_size
&&
604 memcmp(a
->ds
.digest
, b
->ds
.digest
, a
->ds
.digest_size
) == 0;
607 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
608 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
609 a
->sshfp
.fingerprint_size
== b
->sshfp
.fingerprint_size
&&
610 memcmp(a
->sshfp
.fingerprint
, b
->sshfp
.fingerprint
, a
->sshfp
.fingerprint_size
) == 0;
612 case DNS_TYPE_DNSKEY
:
613 return a
->dnskey
.flags
== b
->dnskey
.flags
&&
614 a
->dnskey
.protocol
== b
->dnskey
.protocol
&&
615 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
616 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
617 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
620 /* do the fast comparisons first */
621 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
622 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
623 a
->rrsig
.labels
!= b
->rrsig
.labels
||
624 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
625 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
626 a
->rrsig
.inception
!= b
->rrsig
.inception
||
627 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
628 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
629 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
632 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
635 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
636 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
639 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
640 a
->nsec3
.flags
== b
->nsec3
.flags
&&
641 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
642 a
->nsec3
.salt_size
== b
->nsec3
.salt_size
&&
643 memcmp(a
->nsec3
.salt
, b
->nsec3
.salt
, a
->nsec3
.salt_size
) == 0 &&
644 memcmp(a
->nsec3
.next_hashed_name
, b
->nsec3
.next_hashed_name
, a
->nsec3
.next_hashed_name_size
) == 0 &&
645 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
648 return a
->generic
.size
== b
->generic
.size
&&
649 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
653 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
654 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
656 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
657 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
659 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
660 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
661 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
662 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
663 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
664 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
666 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
669 (lat
% 60000) / 1000.,
673 (lon
% 60000) / 1000.,
684 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
688 assert(l
> strlen("YYYYMMDDHHmmSS"));
690 if (!gmtime_r(&sec
, &tm
))
693 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
699 static char *format_types(Bitmap
*types
) {
700 _cleanup_strv_free_
char **strv
= NULL
;
701 _cleanup_free_
char *str
= NULL
;
706 BITMAP_FOREACH(type
, types
, i
) {
707 if (dns_type_to_string(type
)) {
708 r
= strv_extend(&strv
, dns_type_to_string(type
));
714 r
= asprintf(&t
, "TYPE%u", type
);
718 r
= strv_consume(&strv
, t
);
724 str
= strv_join(strv
, " ");
728 return strjoin("( ", str
, " )", NULL
);
731 static char *format_txt(DnsTxtItem
*first
) {
736 LIST_FOREACH(items
, i
, first
)
737 c
+= i
->length
* 4 + 3;
739 p
= s
= new(char, c
);
743 LIST_FOREACH(items
, i
, first
) {
751 for (j
= 0; j
< i
->length
; j
++) {
752 if (i
->data
[j
] < ' ' || i
->data
[j
] == '"' || i
->data
[j
] >= 127) {
754 *(p
++) = '0' + (i
->data
[j
] / 100);
755 *(p
++) = '0' + ((i
->data
[j
] / 10) % 10);
756 *(p
++) = '0' + (i
->data
[j
] % 10);
768 const char *dns_resource_record_to_string(DnsResourceRecord
*rr
) {
769 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
776 return rr
->to_string
;
778 r
= dns_resource_key_to_string(rr
->key
, &k
);
782 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
785 r
= asprintf(&s
, "%s %u %u %u %s",
790 strna(rr
->srv
.name
));
799 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
806 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
811 case DNS_TYPE_SPF
: /* exactly the same as TXT */
813 t
= format_txt(rr
->txt
.items
);
817 s
= strjoin(k
, " ", t
, NULL
);
823 _cleanup_free_
char *x
= NULL
;
825 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
829 s
= strjoin(k
, " ", x
, NULL
);
836 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
840 s
= strjoin(k
, " ", t
, NULL
);
846 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
848 strna(rr
->soa
.mname
),
849 strna(rr
->soa
.rname
),
860 r
= asprintf(&s
, "%s %u %s",
869 assert(rr
->loc
.version
== 0);
871 t
= format_location(rr
->loc
.latitude
,
880 s
= strjoin(k
, " ", t
, NULL
);
886 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
890 r
= asprintf(&s
, "%s %u %u %u %s",
901 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
905 r
= asprintf(&s
, "%s %u %u %s",
914 case DNS_TYPE_DNSKEY
: {
917 alg
= dnssec_algorithm_to_string(rr
->dnskey
.algorithm
);
919 t
= base64mem(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
923 r
= asprintf(&s
, "%s %u %u %.*s%.*u %s",
928 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->dnskey
.algorithm
,
935 case DNS_TYPE_RRSIG
: {
936 const char *type
, *alg
;
937 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
939 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
940 alg
= dnssec_algorithm_to_string(rr
->rrsig
.algorithm
);
942 t
= base64mem(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
946 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
950 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
955 * http://tools.ietf.org/html/rfc3597#section-5 */
957 r
= asprintf(&s
, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
960 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
962 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->rrsig
.algorithm
,
964 rr
->rrsig
.original_ttl
,
976 t
= format_types(rr
->nsec
.types
);
980 r
= asprintf(&s
, "%s %s %s",
982 rr
->nsec
.next_domain_name
,
988 case DNS_TYPE_NSEC3
: {
989 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
991 if (rr
->nsec3
.salt_size
> 0) {
992 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
997 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
1001 t
= format_types(rr
->nsec3
.types
);
1005 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
1007 rr
->nsec3
.algorithm
,
1009 rr
->nsec3
.iterations
,
1010 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
1020 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
1024 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.size
, t
);
1034 int dns_resource_record_to_wire_format(DnsResourceRecord
*rr
, bool canonical
) {
1036 DnsPacket packet
= {
1038 .protocol
= DNS_PROTOCOL_DNS
,
1040 .refuse_compression
= true,
1041 .canonical_form
= canonical
,
1049 /* Generates the RR in wire-format, optionally in the
1050 * canonical form as discussed in the DNSSEC RFC 4034, Section
1051 * 6.2. We allocate a throw-away DnsPacket object on the stack
1052 * here, because we need some book-keeping for memory
1053 * management, and can reuse the DnsPacket serializer, that
1054 * can generate the canonical form, too, but also knows label
1055 * compression and suchlike. */
1057 if (rr
->wire_format
&& rr
->wire_format_canonical
== canonical
)
1060 r
= dns_packet_append_rr(&packet
, rr
, &start
, &rds
);
1065 assert(packet
._data
);
1067 free(rr
->wire_format
);
1068 rr
->wire_format
= packet
._data
;
1069 rr
->wire_format_size
= packet
.size
;
1070 rr
->wire_format_rdata_offset
= rds
;
1071 rr
->wire_format_canonical
= canonical
;
1073 packet
._data
= NULL
;
1074 dns_packet_unref(&packet
);
1079 DnsTxtItem
*dns_txt_item_free_all(DnsTxtItem
*i
) {
1088 return dns_txt_item_free_all(n
);
1091 bool dns_txt_item_equal(DnsTxtItem
*a
, DnsTxtItem
*b
) {
1102 if (a
->length
!= b
->length
)
1105 if (memcmp(a
->data
, b
->data
, a
->length
) != 0)
1108 return dns_txt_item_equal(a
->items_next
, b
->items_next
);
1111 static const char* const dnssec_algorithm_table
[_DNSSEC_ALGORITHM_MAX_DEFINED
] = {
1112 [DNSSEC_ALGORITHM_RSAMD5
] = "RSAMD5",
1113 [DNSSEC_ALGORITHM_DH
] = "DH",
1114 [DNSSEC_ALGORITHM_DSA
] = "DSA",
1115 [DNSSEC_ALGORITHM_ECC
] = "ECC",
1116 [DNSSEC_ALGORITHM_RSASHA1
] = "RSASHA1",
1117 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1
] = "DSA-NSEC3-SHA1",
1118 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
] = "RSASHA1-NSEC3-SHA1",
1119 [DNSSEC_ALGORITHM_RSASHA256
] = "RSASHA256",
1120 [DNSSEC_ALGORITHM_RSASHA512
] = "RSASHA512",
1121 [DNSSEC_ALGORITHM_INDIRECT
] = "INDIRECT",
1122 [DNSSEC_ALGORITHM_PRIVATEDNS
] = "PRIVATEDNS",
1123 [DNSSEC_ALGORITHM_PRIVATEOID
] = "PRIVATEOID",
1125 DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm
, int);
1127 static const char* const dnssec_digest_table
[_DNSSEC_DIGEST_MAX_DEFINED
] = {
1128 [DNSSEC_DIGEST_SHA1
] = "SHA1",
1129 [DNSSEC_DIGEST_SHA256
] = "SHA256",
1131 DEFINE_STRING_TABLE_LOOKUP(dnssec_digest
, int);