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
, const 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(const DnsResourceKey
*key
, const DnsResourceRecord
*rr
, const char *search_domain
) {
229 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
232 if (rr
->key
->type
== DNS_TYPE_CNAME
)
233 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(rr
->key
));
234 else if (rr
->key
->type
== DNS_TYPE_DNAME
)
235 r
= dns_name_endswith(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(rr
->key
));
243 _cleanup_free_
char *joined
= NULL
;
245 r
= dns_name_concat(DNS_RESOURCE_KEY_NAME(key
), search_domain
, &joined
);
249 if (rr
->key
->type
== DNS_TYPE_CNAME
)
250 return dns_name_equal(joined
, DNS_RESOURCE_KEY_NAME(rr
->key
));
251 else if (rr
->key
->type
== DNS_TYPE_DNAME
)
252 return dns_name_endswith(joined
, DNS_RESOURCE_KEY_NAME(rr
->key
));
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 != DNS_CLASS_IN
)
267 if (soa
->type
!= DNS_TYPE_SOA
)
270 if (!dns_name_endswith(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(soa
)))
276 static void dns_resource_key_hash_func(const void *i
, struct siphash
*state
) {
277 const DnsResourceKey
*k
= i
;
281 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k
), state
);
282 siphash24_compress(&k
->class, sizeof(k
->class), state
);
283 siphash24_compress(&k
->type
, sizeof(k
->type
), state
);
286 static int dns_resource_key_compare_func(const void *a
, const void *b
) {
287 const DnsResourceKey
*x
= a
, *y
= b
;
290 ret
= dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x
), DNS_RESOURCE_KEY_NAME(y
));
294 if (x
->type
< y
->type
)
296 if (x
->type
> y
->type
)
299 if (x
->class < y
->class)
301 if (x
->class > y
->class)
307 const struct hash_ops dns_resource_key_hash_ops
= {
308 .hash
= dns_resource_key_hash_func
,
309 .compare
= dns_resource_key_compare_func
312 int dns_resource_key_to_string(const DnsResourceKey
*key
, char **ret
) {
313 char cbuf
[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf
[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
317 c
= dns_class_to_string(key
->class);
319 sprintf(cbuf
, "CLASS%u", key
->class);
323 t
= dns_type_to_string(key
->type
);
325 sprintf(tbuf
, "TYPE%u", key
->type
);
329 if (asprintf(&s
, "%s. %s %-5s", DNS_RESOURCE_KEY_NAME(key
), c
, t
) < 0)
336 DnsResourceRecord
* dns_resource_record_new(DnsResourceKey
*key
) {
337 DnsResourceRecord
*rr
;
339 rr
= new0(DnsResourceRecord
, 1);
344 rr
->key
= dns_resource_key_ref(key
);
349 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
350 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
352 key
= dns_resource_key_new(class, type
, name
);
356 return dns_resource_record_new(key
);
359 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
363 assert(rr
->n_ref
> 0);
369 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
373 assert(rr
->n_ref
> 0);
381 switch(rr
->key
->type
) {
401 dns_txt_item_free_all(rr
->txt
.items
);
410 free(rr
->mx
.exchange
);
418 free(rr
->sshfp
.fingerprint
);
421 case DNS_TYPE_DNSKEY
:
422 free(rr
->dnskey
.key
);
426 free(rr
->rrsig
.signer
);
427 free(rr
->rrsig
.signature
);
431 free(rr
->nsec
.next_domain_name
);
432 bitmap_free(rr
->nsec
.types
);
436 free(rr
->nsec3
.next_hashed_name
);
437 free(rr
->nsec3
.salt
);
438 bitmap_free(rr
->nsec3
.types
);
447 free(rr
->generic
.data
);
450 free(rr
->wire_format
);
451 dns_resource_key_unref(rr
->key
);
459 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
460 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
461 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
462 _cleanup_free_
char *ptr
= NULL
;
469 r
= dns_name_reverse(family
, address
, &ptr
);
473 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
479 rr
= dns_resource_record_new(key
);
483 rr
->ptr
.name
= strdup(hostname
);
493 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
494 DnsResourceRecord
*rr
;
500 if (family
== AF_INET
) {
502 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
506 rr
->a
.in_addr
= address
->in
;
508 } else if (family
== AF_INET6
) {
510 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
514 rr
->aaaa
.in6_addr
= address
->in6
;
516 return -EAFNOSUPPORT
;
523 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
532 r
= dns_resource_key_equal(a
->key
, b
->key
);
536 if (a
->unparseable
!= b
->unparseable
)
539 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
542 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
546 return a
->srv
.priority
== b
->srv
.priority
&&
547 a
->srv
.weight
== b
->srv
.weight
&&
548 a
->srv
.port
== b
->srv
.port
;
554 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
557 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
558 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
560 case DNS_TYPE_SPF
: /* exactly the same as TXT */
562 return dns_txt_item_equal(a
->txt
.items
, b
->txt
.items
);
565 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
568 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
571 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
574 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
578 return a
->soa
.serial
== b
->soa
.serial
&&
579 a
->soa
.refresh
== b
->soa
.refresh
&&
580 a
->soa
.retry
== b
->soa
.retry
&&
581 a
->soa
.expire
== b
->soa
.expire
&&
582 a
->soa
.minimum
== b
->soa
.minimum
;
585 if (a
->mx
.priority
!= b
->mx
.priority
)
588 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
591 assert(a
->loc
.version
== b
->loc
.version
);
593 return a
->loc
.size
== b
->loc
.size
&&
594 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
595 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
596 a
->loc
.latitude
== b
->loc
.latitude
&&
597 a
->loc
.longitude
== b
->loc
.longitude
&&
598 a
->loc
.altitude
== b
->loc
.altitude
;
601 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
602 a
->ds
.algorithm
== b
->ds
.algorithm
&&
603 a
->ds
.digest_type
== b
->ds
.digest_type
&&
604 a
->ds
.digest_size
== b
->ds
.digest_size
&&
605 memcmp(a
->ds
.digest
, b
->ds
.digest
, a
->ds
.digest_size
) == 0;
608 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
609 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
610 a
->sshfp
.fingerprint_size
== b
->sshfp
.fingerprint_size
&&
611 memcmp(a
->sshfp
.fingerprint
, b
->sshfp
.fingerprint
, a
->sshfp
.fingerprint_size
) == 0;
613 case DNS_TYPE_DNSKEY
:
614 return a
->dnskey
.flags
== b
->dnskey
.flags
&&
615 a
->dnskey
.protocol
== b
->dnskey
.protocol
&&
616 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
617 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
618 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
621 /* do the fast comparisons first */
622 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
623 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
624 a
->rrsig
.labels
!= b
->rrsig
.labels
||
625 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
626 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
627 a
->rrsig
.inception
!= b
->rrsig
.inception
||
628 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
629 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
630 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
633 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
636 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
637 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
640 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
641 a
->nsec3
.flags
== b
->nsec3
.flags
&&
642 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
643 a
->nsec3
.salt_size
== b
->nsec3
.salt_size
&&
644 memcmp(a
->nsec3
.salt
, b
->nsec3
.salt
, a
->nsec3
.salt_size
) == 0 &&
645 memcmp(a
->nsec3
.next_hashed_name
, b
->nsec3
.next_hashed_name
, a
->nsec3
.next_hashed_name_size
) == 0 &&
646 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
649 return a
->generic
.size
== b
->generic
.size
&&
650 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
654 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
655 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
657 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
658 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
660 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
661 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
662 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
663 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
664 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
665 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
667 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
670 (lat
% 60000) / 1000.,
674 (lon
% 60000) / 1000.,
685 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
689 assert(l
> strlen("YYYYMMDDHHmmSS"));
691 if (!gmtime_r(&sec
, &tm
))
694 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
700 static char *format_types(Bitmap
*types
) {
701 _cleanup_strv_free_
char **strv
= NULL
;
702 _cleanup_free_
char *str
= NULL
;
707 BITMAP_FOREACH(type
, types
, i
) {
708 if (dns_type_to_string(type
)) {
709 r
= strv_extend(&strv
, dns_type_to_string(type
));
715 r
= asprintf(&t
, "TYPE%u", type
);
719 r
= strv_consume(&strv
, t
);
725 str
= strv_join(strv
, " ");
729 return strjoin("( ", str
, " )", NULL
);
732 static char *format_txt(DnsTxtItem
*first
) {
737 LIST_FOREACH(items
, i
, first
)
738 c
+= i
->length
* 4 + 3;
740 p
= s
= new(char, c
);
744 LIST_FOREACH(items
, i
, first
) {
752 for (j
= 0; j
< i
->length
; j
++) {
753 if (i
->data
[j
] < ' ' || i
->data
[j
] == '"' || i
->data
[j
] >= 127) {
755 *(p
++) = '0' + (i
->data
[j
] / 100);
756 *(p
++) = '0' + ((i
->data
[j
] / 10) % 10);
757 *(p
++) = '0' + (i
->data
[j
] % 10);
769 int dns_resource_record_to_string(const DnsResourceRecord
*rr
, char **ret
) {
770 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
776 r
= dns_resource_key_to_string(rr
->key
, &k
);
780 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
783 r
= asprintf(&s
, "%s %u %u %u %s",
788 strna(rr
->srv
.name
));
797 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
804 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
809 case DNS_TYPE_SPF
: /* exactly the same as TXT */
811 t
= format_txt(rr
->txt
.items
);
815 s
= strjoin(k
, " ", t
, NULL
);
821 _cleanup_free_
char *x
= NULL
;
823 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
827 s
= strjoin(k
, " ", x
, NULL
);
834 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
838 s
= strjoin(k
, " ", t
, NULL
);
844 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
846 strna(rr
->soa
.mname
),
847 strna(rr
->soa
.rname
),
858 r
= asprintf(&s
, "%s %u %s",
867 assert(rr
->loc
.version
== 0);
869 t
= format_location(rr
->loc
.latitude
,
878 s
= strjoin(k
, " ", t
, NULL
);
884 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
888 r
= asprintf(&s
, "%s %u %u %u %s",
899 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
903 r
= asprintf(&s
, "%s %u %u %s",
912 case DNS_TYPE_DNSKEY
: {
915 alg
= dnssec_algorithm_to_string(rr
->dnskey
.algorithm
);
917 t
= base64mem(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
921 r
= asprintf(&s
, "%s %u %u %.*s%.*u %s",
926 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->dnskey
.algorithm
,
933 case DNS_TYPE_RRSIG
: {
934 const char *type
, *alg
;
935 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
937 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
938 alg
= dnssec_algorithm_to_string(rr
->rrsig
.algorithm
);
940 t
= base64mem(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
944 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
948 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
953 * http://tools.ietf.org/html/rfc3597#section-5 */
955 r
= asprintf(&s
, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
958 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
960 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->rrsig
.algorithm
,
962 rr
->rrsig
.original_ttl
,
974 t
= format_types(rr
->nsec
.types
);
978 r
= asprintf(&s
, "%s %s %s",
980 rr
->nsec
.next_domain_name
,
986 case DNS_TYPE_NSEC3
: {
987 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
989 if (rr
->nsec3
.salt_size
> 0) {
990 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
995 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
999 t
= format_types(rr
->nsec3
.types
);
1003 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
1005 rr
->nsec3
.algorithm
,
1007 rr
->nsec3
.iterations
,
1008 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
1018 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
1022 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.size
, t
);
1032 int dns_resource_record_to_wire_format(DnsResourceRecord
*rr
, bool canonical
) {
1034 DnsPacket packet
= {
1036 .protocol
= DNS_PROTOCOL_DNS
,
1038 .refuse_compression
= true,
1039 .canonical_form
= canonical
,
1047 /* Generates the RR in wire-format, optionally in the
1048 * canonical form as discussed in the DNSSEC RFC 4034, Section
1049 * 6.2. We allocate a throw-away DnsPacket object on the stack
1050 * here, because we need some book-keeping for memory
1051 * management, and can reuse the DnsPacket serializer, that
1052 * can generate the canonical form, too, but also knows label
1053 * compression and suchlike. */
1055 if (rr
->wire_format
&& rr
->wire_format_canonical
== canonical
)
1058 r
= dns_packet_append_rr(&packet
, rr
, &start
, &rds
);
1063 assert(packet
._data
);
1065 free(rr
->wire_format
);
1066 rr
->wire_format
= packet
._data
;
1067 rr
->wire_format_size
= packet
.size
;
1068 rr
->wire_format_rdata_offset
= rds
;
1069 rr
->wire_format_canonical
= canonical
;
1071 packet
._data
= NULL
;
1072 dns_packet_unref(&packet
);
1077 const char *dns_class_to_string(uint16_t class) {
1091 int dns_class_from_string(const char *s
, uint16_t *class) {
1095 if (strcaseeq(s
, "IN"))
1096 *class = DNS_CLASS_IN
;
1097 else if (strcaseeq(s
, "ANY"))
1098 *class = DNS_CLASS_ANY
;
1105 DnsTxtItem
*dns_txt_item_free_all(DnsTxtItem
*i
) {
1114 return dns_txt_item_free_all(n
);
1117 bool dns_txt_item_equal(DnsTxtItem
*a
, DnsTxtItem
*b
) {
1128 if (a
->length
!= b
->length
)
1131 if (memcmp(a
->data
, b
->data
, a
->length
) != 0)
1134 return dns_txt_item_equal(a
->items_next
, b
->items_next
);
1137 static const char* const dnssec_algorithm_table
[_DNSSEC_ALGORITHM_MAX_DEFINED
] = {
1138 [DNSSEC_ALGORITHM_RSAMD5
] = "RSAMD5",
1139 [DNSSEC_ALGORITHM_DH
] = "DH",
1140 [DNSSEC_ALGORITHM_DSA
] = "DSA",
1141 [DNSSEC_ALGORITHM_ECC
] = "ECC",
1142 [DNSSEC_ALGORITHM_RSASHA1
] = "RSASHA1",
1143 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1
] = "DSA-NSEC3-SHA1",
1144 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
] = "RSASHA1-NSEC3-SHA1",
1145 [DNSSEC_ALGORITHM_RSASHA256
] = "RSASHA256",
1146 [DNSSEC_ALGORITHM_RSASHA512
] = "RSASHA512",
1147 [DNSSEC_ALGORITHM_INDIRECT
] = "INDIRECT",
1148 [DNSSEC_ALGORITHM_PRIVATEDNS
] = "PRIVATEDNS",
1149 [DNSSEC_ALGORITHM_PRIVATEOID
] = "PRIVATEOID",
1151 DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm
, int);
1153 static const char* const dnssec_digest_table
[_DNSSEC_DIGEST_MAX_DEFINED
] = {
1154 [DNSSEC_DIGEST_SHA1
] = "SHA1",
1155 [DNSSEC_DIGEST_SHA256
] = "SHA256",
1157 DEFINE_STRING_TABLE_LOOKUP(dnssec_digest
, int);