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_cname(const DnsResourceKey
*key
) {
57 return dns_resource_key_new(key
->class, DNS_TYPE_CNAME
, DNS_RESOURCE_KEY_NAME(key
));
60 DnsResourceKey
* dns_resource_key_new_redirect(const DnsResourceKey
*key
, const DnsResourceRecord
*cname
) {
66 assert(IN_SET(cname
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
));
68 if (cname
->key
->type
== DNS_TYPE_CNAME
)
69 return dns_resource_key_new(key
->class, key
->type
, cname
->cname
.name
);
72 char *destination
= NULL
;
74 r
= dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(cname
->key
), cname
->dname
.name
, &destination
);
78 return dns_resource_key_ref((DnsResourceKey
*) key
);
80 k
= dns_resource_key_new_consume(key
->class, key
->type
, destination
);
90 int dns_resource_key_new_append_suffix(DnsResourceKey
**ret
, DnsResourceKey
*key
, char *name
) {
91 DnsResourceKey
*new_key
;
99 if (dns_name_is_root(name
)) {
100 *ret
= dns_resource_key_ref(key
);
104 r
= dns_name_concat(DNS_RESOURCE_KEY_NAME(key
), name
, &joined
);
108 new_key
= dns_resource_key_new_consume(key
->class, key
->type
, joined
);
118 DnsResourceKey
* dns_resource_key_new_consume(uint16_t class, uint16_t type
, char *name
) {
123 k
= new0(DnsResourceKey
, 1);
135 DnsResourceKey
* dns_resource_key_ref(DnsResourceKey
*k
) {
140 assert(k
->n_ref
> 0);
146 DnsResourceKey
* dns_resource_key_unref(DnsResourceKey
*k
) {
150 assert(k
->n_ref
> 0);
161 int dns_resource_key_equal(const DnsResourceKey
*a
, const DnsResourceKey
*b
) {
164 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(a
), DNS_RESOURCE_KEY_NAME(b
));
168 if (a
->class != b
->class)
171 if (a
->type
!= b
->type
)
177 int dns_resource_key_match_rr(const DnsResourceKey
*key
, const DnsResourceRecord
*rr
, const char *search_domain
) {
183 /* Checks if an rr matches the specified key. If a search
184 * domain is specified, it will also be checked if the key
185 * with the search domain suffixed might match the RR. */
187 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
190 if (rr
->key
->type
!= key
->type
&& key
->type
!= DNS_TYPE_ANY
)
193 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
198 _cleanup_free_
char *joined
= NULL
;
200 r
= dns_name_concat(DNS_RESOURCE_KEY_NAME(key
), search_domain
, &joined
);
204 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), joined
);
210 int dns_resource_key_match_cname(const DnsResourceKey
*key
, const DnsResourceRecord
*rr
, const char *search_domain
) {
216 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
219 if (rr
->key
->type
== DNS_TYPE_CNAME
)
220 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(rr
->key
));
221 else if (rr
->key
->type
== DNS_TYPE_DNAME
)
222 r
= dns_name_endswith(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(rr
->key
));
230 _cleanup_free_
char *joined
= NULL
;
232 r
= dns_name_concat(DNS_RESOURCE_KEY_NAME(key
), search_domain
, &joined
);
236 if (rr
->key
->type
== DNS_TYPE_CNAME
)
237 return dns_name_equal(joined
, DNS_RESOURCE_KEY_NAME(rr
->key
));
238 else if (rr
->key
->type
== DNS_TYPE_DNAME
)
239 return dns_name_endswith(joined
, DNS_RESOURCE_KEY_NAME(rr
->key
));
246 static void dns_resource_key_hash_func(const void *i
, struct siphash
*state
) {
247 const DnsResourceKey
*k
= i
;
251 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k
), state
);
252 siphash24_compress(&k
->class, sizeof(k
->class), state
);
253 siphash24_compress(&k
->type
, sizeof(k
->type
), state
);
256 static int dns_resource_key_compare_func(const void *a
, const void *b
) {
257 const DnsResourceKey
*x
= a
, *y
= b
;
260 ret
= dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x
), DNS_RESOURCE_KEY_NAME(y
));
264 if (x
->type
< y
->type
)
266 if (x
->type
> y
->type
)
269 if (x
->class < y
->class)
271 if (x
->class > y
->class)
277 const struct hash_ops dns_resource_key_hash_ops
= {
278 .hash
= dns_resource_key_hash_func
,
279 .compare
= dns_resource_key_compare_func
282 int dns_resource_key_to_string(const DnsResourceKey
*key
, char **ret
) {
283 char cbuf
[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf
[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
287 c
= dns_class_to_string(key
->class);
289 sprintf(cbuf
, "CLASS%u", key
->class);
293 t
= dns_type_to_string(key
->type
);
295 sprintf(tbuf
, "TYPE%u", key
->type
);
299 if (asprintf(&s
, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key
), c
, t
) < 0)
306 DnsResourceRecord
* dns_resource_record_new(DnsResourceKey
*key
) {
307 DnsResourceRecord
*rr
;
309 rr
= new0(DnsResourceRecord
, 1);
314 rr
->key
= dns_resource_key_ref(key
);
319 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
320 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
322 key
= dns_resource_key_new(class, type
, name
);
326 return dns_resource_record_new(key
);
329 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
333 assert(rr
->n_ref
> 0);
339 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
343 assert(rr
->n_ref
> 0);
351 switch(rr
->key
->type
) {
371 dns_txt_item_free_all(rr
->txt
.items
);
380 free(rr
->mx
.exchange
);
388 free(rr
->sshfp
.fingerprint
);
391 case DNS_TYPE_DNSKEY
:
392 free(rr
->dnskey
.key
);
396 free(rr
->rrsig
.signer
);
397 free(rr
->rrsig
.signature
);
401 free(rr
->nsec
.next_domain_name
);
402 bitmap_free(rr
->nsec
.types
);
406 free(rr
->nsec3
.next_hashed_name
);
407 free(rr
->nsec3
.salt
);
408 bitmap_free(rr
->nsec3
.types
);
417 free(rr
->generic
.data
);
420 free(rr
->wire_format
);
421 dns_resource_key_unref(rr
->key
);
429 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
430 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
431 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
432 _cleanup_free_
char *ptr
= NULL
;
439 r
= dns_name_reverse(family
, address
, &ptr
);
443 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
449 rr
= dns_resource_record_new(key
);
453 rr
->ptr
.name
= strdup(hostname
);
463 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
464 DnsResourceRecord
*rr
;
470 if (family
== AF_INET
) {
472 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
476 rr
->a
.in_addr
= address
->in
;
478 } else if (family
== AF_INET6
) {
480 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
484 rr
->aaaa
.in6_addr
= address
->in6
;
486 return -EAFNOSUPPORT
;
493 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
499 r
= dns_resource_key_equal(a
->key
, b
->key
);
503 if (a
->unparseable
!= b
->unparseable
)
506 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
509 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
513 return a
->srv
.priority
== b
->srv
.priority
&&
514 a
->srv
.weight
== b
->srv
.weight
&&
515 a
->srv
.port
== b
->srv
.port
;
521 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
524 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
525 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
527 case DNS_TYPE_SPF
: /* exactly the same as TXT */
529 return dns_txt_item_equal(a
->txt
.items
, b
->txt
.items
);
532 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
535 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
538 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
541 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
545 return a
->soa
.serial
== b
->soa
.serial
&&
546 a
->soa
.refresh
== b
->soa
.refresh
&&
547 a
->soa
.retry
== b
->soa
.retry
&&
548 a
->soa
.expire
== b
->soa
.expire
&&
549 a
->soa
.minimum
== b
->soa
.minimum
;
552 if (a
->mx
.priority
!= b
->mx
.priority
)
555 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
558 assert(a
->loc
.version
== b
->loc
.version
);
560 return a
->loc
.size
== b
->loc
.size
&&
561 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
562 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
563 a
->loc
.latitude
== b
->loc
.latitude
&&
564 a
->loc
.longitude
== b
->loc
.longitude
&&
565 a
->loc
.altitude
== b
->loc
.altitude
;
568 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
569 a
->ds
.algorithm
== b
->ds
.algorithm
&&
570 a
->ds
.digest_type
== b
->ds
.digest_type
&&
571 a
->ds
.digest_size
== b
->ds
.digest_size
&&
572 memcmp(a
->ds
.digest
, b
->ds
.digest
, a
->ds
.digest_size
) == 0;
575 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
576 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
577 a
->sshfp
.fingerprint_size
== b
->sshfp
.fingerprint_size
&&
578 memcmp(a
->sshfp
.fingerprint
, b
->sshfp
.fingerprint
, a
->sshfp
.fingerprint_size
) == 0;
580 case DNS_TYPE_DNSKEY
:
581 return a
->dnskey
.flags
== b
->dnskey
.flags
&&
582 a
->dnskey
.protocol
== b
->dnskey
.protocol
&&
583 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
584 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
585 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
588 /* do the fast comparisons first */
589 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
590 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
591 a
->rrsig
.labels
!= b
->rrsig
.labels
||
592 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
593 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
594 a
->rrsig
.inception
!= b
->rrsig
.inception
||
595 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
596 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
597 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
600 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
603 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
604 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
607 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
608 a
->nsec3
.flags
== b
->nsec3
.flags
&&
609 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
610 a
->nsec3
.salt_size
== b
->nsec3
.salt_size
&&
611 memcmp(a
->nsec3
.salt
, b
->nsec3
.salt
, a
->nsec3
.salt_size
) == 0 &&
612 memcmp(a
->nsec3
.next_hashed_name
, b
->nsec3
.next_hashed_name
, a
->nsec3
.next_hashed_name_size
) == 0 &&
613 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
616 return a
->generic
.size
== b
->generic
.size
&&
617 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
621 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
622 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
624 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
625 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
627 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
628 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
629 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
630 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
631 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
632 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
634 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
637 (lat
% 60000) / 1000.,
641 (lon
% 60000) / 1000.,
652 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
656 assert(l
> strlen("YYYYMMDDHHmmSS"));
658 if (!gmtime_r(&sec
, &tm
))
661 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
667 static char *format_types(Bitmap
*types
) {
668 _cleanup_strv_free_
char **strv
= NULL
;
669 _cleanup_free_
char *str
= NULL
;
674 BITMAP_FOREACH(type
, types
, i
) {
675 if (dns_type_to_string(type
)) {
676 r
= strv_extend(&strv
, dns_type_to_string(type
));
682 r
= asprintf(&t
, "TYPE%u", type
);
686 r
= strv_consume(&strv
, t
);
692 str
= strv_join(strv
, " ");
696 return strjoin("( ", str
, " )", NULL
);
699 static char *format_txt(DnsTxtItem
*first
) {
704 LIST_FOREACH(items
, i
, first
)
705 c
+= i
->length
* 4 + 3;
707 p
= s
= new(char, c
);
711 LIST_FOREACH(items
, i
, first
) {
719 for (j
= 0; j
< i
->length
; j
++) {
720 if (i
->data
[j
] < ' ' || i
->data
[j
] == '"' || i
->data
[j
] >= 127) {
722 *(p
++) = '0' + (i
->data
[j
] / 100);
723 *(p
++) = '0' + ((i
->data
[j
] / 10) % 10);
724 *(p
++) = '0' + (i
->data
[j
] % 10);
736 int dns_resource_record_to_string(const DnsResourceRecord
*rr
, char **ret
) {
737 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
743 r
= dns_resource_key_to_string(rr
->key
, &k
);
747 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
750 r
= asprintf(&s
, "%s %u %u %u %s",
755 strna(rr
->srv
.name
));
764 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
771 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
776 case DNS_TYPE_SPF
: /* exactly the same as TXT */
778 t
= format_txt(rr
->txt
.items
);
782 s
= strjoin(k
, " ", t
, NULL
);
788 _cleanup_free_
char *x
= NULL
;
790 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
794 s
= strjoin(k
, " ", x
, NULL
);
801 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
805 s
= strjoin(k
, " ", t
, NULL
);
811 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
813 strna(rr
->soa
.mname
),
814 strna(rr
->soa
.rname
),
825 r
= asprintf(&s
, "%s %u %s",
834 assert(rr
->loc
.version
== 0);
836 t
= format_location(rr
->loc
.latitude
,
845 s
= strjoin(k
, " ", t
, NULL
);
851 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
855 r
= asprintf(&s
, "%s %u %u %u %s",
866 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
870 r
= asprintf(&s
, "%s %u %u %s",
879 case DNS_TYPE_DNSKEY
: {
882 alg
= dnssec_algorithm_to_string(rr
->dnskey
.algorithm
);
884 t
= base64mem(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
888 r
= asprintf(&s
, "%s %u %u %.*s%.*u %s",
893 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->dnskey
.algorithm
,
900 case DNS_TYPE_RRSIG
: {
901 const char *type
, *alg
;
902 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
904 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
905 alg
= dnssec_algorithm_to_string(rr
->rrsig
.algorithm
);
907 t
= base64mem(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
911 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
915 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
920 * http://tools.ietf.org/html/rfc3597#section-5 */
922 r
= asprintf(&s
, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
925 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
927 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->rrsig
.algorithm
,
929 rr
->rrsig
.original_ttl
,
941 t
= format_types(rr
->nsec
.types
);
945 r
= asprintf(&s
, "%s %s %s",
947 rr
->nsec
.next_domain_name
,
953 case DNS_TYPE_NSEC3
: {
954 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
956 if (rr
->nsec3
.salt_size
> 0) {
957 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
962 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
966 t
= format_types(rr
->nsec3
.types
);
970 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
974 rr
->nsec3
.iterations
,
975 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
985 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
989 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.size
, t
);
999 int dns_resource_record_to_wire_format(DnsResourceRecord
*rr
, bool canonical
) {
1001 DnsPacket packet
= {
1003 .protocol
= DNS_PROTOCOL_DNS
,
1005 .refuse_compression
= true,
1006 .canonical_form
= canonical
,
1014 /* Generates the RR in wire-format, optionally in the
1015 * canonical form as discussed in the DNSSEC RFC 4034, Section
1016 * 6.2. We allocate a throw-away DnsPacket object on the stack
1017 * here, because we need some book-keeping for memory
1018 * management, and can reuse the DnsPacket serializer, that
1019 * can generate the canonical form, too, but also knows label
1020 * compression and suchlike. */
1022 if (rr
->wire_format
&& rr
->wire_format_canonical
== canonical
)
1025 r
= dns_packet_append_rr(&packet
, rr
, &start
, &rds
);
1030 assert(packet
._data
);
1032 free(rr
->wire_format
);
1033 rr
->wire_format
= packet
._data
;
1034 rr
->wire_format_size
= packet
.size
;
1035 rr
->wire_format_rdata_offset
= rds
;
1036 rr
->wire_format_canonical
= canonical
;
1038 packet
._data
= NULL
;
1039 dns_packet_unref(&packet
);
1044 const char *dns_class_to_string(uint16_t class) {
1058 int dns_class_from_string(const char *s
, uint16_t *class) {
1062 if (strcaseeq(s
, "IN"))
1063 *class = DNS_CLASS_IN
;
1064 else if (strcaseeq(s
, "ANY"))
1065 *class = DNS_CLASS_ANY
;
1072 DnsTxtItem
*dns_txt_item_free_all(DnsTxtItem
*i
) {
1081 return dns_txt_item_free_all(n
);
1084 bool dns_txt_item_equal(DnsTxtItem
*a
, DnsTxtItem
*b
) {
1092 if (a
->length
!= b
->length
)
1095 if (memcmp(a
->data
, b
->data
, a
->length
) != 0)
1098 return dns_txt_item_equal(a
->items_next
, b
->items_next
);
1101 static const char* const dnssec_algorithm_table
[_DNSSEC_ALGORITHM_MAX_DEFINED
] = {
1102 [DNSSEC_ALGORITHM_RSAMD5
] = "RSAMD5",
1103 [DNSSEC_ALGORITHM_DH
] = "DH",
1104 [DNSSEC_ALGORITHM_DSA
] = "DSA",
1105 [DNSSEC_ALGORITHM_ECC
] = "ECC",
1106 [DNSSEC_ALGORITHM_RSASHA1
] = "RSASHA1",
1107 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1
] = "DSA-NSEC3-SHA1",
1108 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
] = "RSASHA1-NSEC3-SHA1",
1109 [DNSSEC_ALGORITHM_RSASHA256
] = "RSASHA256",
1110 [DNSSEC_ALGORITHM_RSASHA512
] = "RSASHA512",
1111 [DNSSEC_ALGORITHM_INDIRECT
] = "INDIRECT",
1112 [DNSSEC_ALGORITHM_PRIVATEDNS
] = "PRIVATEDNS",
1113 [DNSSEC_ALGORITHM_PRIVATEOID
] = "PRIVATEOID",
1115 DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm
, int);
1117 static const char* const dnssec_digest_table
[_DNSSEC_DIGEST_MAX_DEFINED
] = {
1118 [DNSSEC_DIGEST_SHA1
] = "SHA1",
1119 [DNSSEC_DIGEST_SHA256
] = "SHA256",
1121 DEFINE_STRING_TABLE_LOOKUP(dnssec_digest
, int);