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)];
311 const char *c
, *t
, *n
;
314 /* If we cannot convert the CLASS/TYPE into a known string,
315 use the format recommended by RFC 3597, Section 5. */
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 n
= DNS_RESOURCE_KEY_NAME(key
);
330 if (asprintf(&s
, "%s%s %s %-5s", n
, endswith(n
, ".") ? "" : ".", c
, t
) < 0)
337 DnsResourceRecord
* dns_resource_record_new(DnsResourceKey
*key
) {
338 DnsResourceRecord
*rr
;
340 rr
= new0(DnsResourceRecord
, 1);
345 rr
->key
= dns_resource_key_ref(key
);
346 rr
->expiry
= USEC_INFINITY
;
351 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
352 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
354 key
= dns_resource_key_new(class, type
, name
);
358 return dns_resource_record_new(key
);
361 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
365 assert(rr
->n_ref
> 0);
371 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
375 assert(rr
->n_ref
> 0);
383 switch(rr
->key
->type
) {
403 dns_txt_item_free_all(rr
->txt
.items
);
412 free(rr
->mx
.exchange
);
420 free(rr
->sshfp
.fingerprint
);
423 case DNS_TYPE_DNSKEY
:
424 free(rr
->dnskey
.key
);
428 free(rr
->rrsig
.signer
);
429 free(rr
->rrsig
.signature
);
433 free(rr
->nsec
.next_domain_name
);
434 bitmap_free(rr
->nsec
.types
);
438 free(rr
->nsec3
.next_hashed_name
);
439 free(rr
->nsec3
.salt
);
440 bitmap_free(rr
->nsec3
.types
);
449 free(rr
->generic
.data
);
452 free(rr
->wire_format
);
453 dns_resource_key_unref(rr
->key
);
462 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
463 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
464 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
465 _cleanup_free_
char *ptr
= NULL
;
472 r
= dns_name_reverse(family
, address
, &ptr
);
476 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
482 rr
= dns_resource_record_new(key
);
486 rr
->ptr
.name
= strdup(hostname
);
496 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
497 DnsResourceRecord
*rr
;
503 if (family
== AF_INET
) {
505 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
509 rr
->a
.in_addr
= address
->in
;
511 } else if (family
== AF_INET6
) {
513 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
517 rr
->aaaa
.in6_addr
= address
->in6
;
519 return -EAFNOSUPPORT
;
526 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
535 r
= dns_resource_key_equal(a
->key
, b
->key
);
539 if (a
->unparseable
!= b
->unparseable
)
542 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
545 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
549 return a
->srv
.priority
== b
->srv
.priority
&&
550 a
->srv
.weight
== b
->srv
.weight
&&
551 a
->srv
.port
== b
->srv
.port
;
557 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
560 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
561 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
563 case DNS_TYPE_SPF
: /* exactly the same as TXT */
565 return dns_txt_item_equal(a
->txt
.items
, b
->txt
.items
);
568 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
571 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
574 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
577 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
581 return a
->soa
.serial
== b
->soa
.serial
&&
582 a
->soa
.refresh
== b
->soa
.refresh
&&
583 a
->soa
.retry
== b
->soa
.retry
&&
584 a
->soa
.expire
== b
->soa
.expire
&&
585 a
->soa
.minimum
== b
->soa
.minimum
;
588 if (a
->mx
.priority
!= b
->mx
.priority
)
591 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
594 assert(a
->loc
.version
== b
->loc
.version
);
596 return a
->loc
.size
== b
->loc
.size
&&
597 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
598 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
599 a
->loc
.latitude
== b
->loc
.latitude
&&
600 a
->loc
.longitude
== b
->loc
.longitude
&&
601 a
->loc
.altitude
== b
->loc
.altitude
;
604 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
605 a
->ds
.algorithm
== b
->ds
.algorithm
&&
606 a
->ds
.digest_type
== b
->ds
.digest_type
&&
607 a
->ds
.digest_size
== b
->ds
.digest_size
&&
608 memcmp(a
->ds
.digest
, b
->ds
.digest
, a
->ds
.digest_size
) == 0;
611 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
612 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
613 a
->sshfp
.fingerprint_size
== b
->sshfp
.fingerprint_size
&&
614 memcmp(a
->sshfp
.fingerprint
, b
->sshfp
.fingerprint
, a
->sshfp
.fingerprint_size
) == 0;
616 case DNS_TYPE_DNSKEY
:
617 return a
->dnskey
.flags
== b
->dnskey
.flags
&&
618 a
->dnskey
.protocol
== b
->dnskey
.protocol
&&
619 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
620 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
621 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
624 /* do the fast comparisons first */
625 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
626 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
627 a
->rrsig
.labels
!= b
->rrsig
.labels
||
628 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
629 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
630 a
->rrsig
.inception
!= b
->rrsig
.inception
||
631 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
632 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
633 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
636 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
639 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
640 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
643 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
644 a
->nsec3
.flags
== b
->nsec3
.flags
&&
645 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
646 a
->nsec3
.salt_size
== b
->nsec3
.salt_size
&&
647 memcmp(a
->nsec3
.salt
, b
->nsec3
.salt
, a
->nsec3
.salt_size
) == 0 &&
648 memcmp(a
->nsec3
.next_hashed_name
, b
->nsec3
.next_hashed_name
, a
->nsec3
.next_hashed_name_size
) == 0 &&
649 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
652 return a
->generic
.size
== b
->generic
.size
&&
653 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
657 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
658 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
660 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
661 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
663 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
664 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
665 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
666 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
667 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
668 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
670 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
673 (lat
% 60000) / 1000.,
677 (lon
% 60000) / 1000.,
688 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
692 assert(l
> strlen("YYYYMMDDHHmmSS"));
694 if (!gmtime_r(&sec
, &tm
))
697 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
703 static char *format_types(Bitmap
*types
) {
704 _cleanup_strv_free_
char **strv
= NULL
;
705 _cleanup_free_
char *str
= NULL
;
710 BITMAP_FOREACH(type
, types
, i
) {
711 if (dns_type_to_string(type
)) {
712 r
= strv_extend(&strv
, dns_type_to_string(type
));
718 r
= asprintf(&t
, "TYPE%u", type
);
722 r
= strv_consume(&strv
, t
);
728 str
= strv_join(strv
, " ");
732 return strjoin("( ", str
, " )", NULL
);
735 static char *format_txt(DnsTxtItem
*first
) {
740 LIST_FOREACH(items
, i
, first
)
741 c
+= i
->length
* 4 + 3;
743 p
= s
= new(char, c
);
747 LIST_FOREACH(items
, i
, first
) {
755 for (j
= 0; j
< i
->length
; j
++) {
756 if (i
->data
[j
] < ' ' || i
->data
[j
] == '"' || i
->data
[j
] >= 127) {
758 *(p
++) = '0' + (i
->data
[j
] / 100);
759 *(p
++) = '0' + ((i
->data
[j
] / 10) % 10);
760 *(p
++) = '0' + (i
->data
[j
] % 10);
772 const char *dns_resource_record_to_string(DnsResourceRecord
*rr
) {
773 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
780 return rr
->to_string
;
782 r
= dns_resource_key_to_string(rr
->key
, &k
);
786 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
789 r
= asprintf(&s
, "%s %u %u %u %s",
794 strna(rr
->srv
.name
));
803 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
810 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
815 case DNS_TYPE_SPF
: /* exactly the same as TXT */
817 t
= format_txt(rr
->txt
.items
);
821 s
= strjoin(k
, " ", t
, NULL
);
827 _cleanup_free_
char *x
= NULL
;
829 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
833 s
= strjoin(k
, " ", x
, NULL
);
840 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
844 s
= strjoin(k
, " ", t
, NULL
);
850 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
852 strna(rr
->soa
.mname
),
853 strna(rr
->soa
.rname
),
864 r
= asprintf(&s
, "%s %u %s",
873 assert(rr
->loc
.version
== 0);
875 t
= format_location(rr
->loc
.latitude
,
884 s
= strjoin(k
, " ", t
, NULL
);
890 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
894 r
= asprintf(&s
, "%s %u %u %u %s",
905 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
909 r
= asprintf(&s
, "%s %u %u %s",
918 case DNS_TYPE_DNSKEY
: {
919 _cleanup_free_
char *alg
= NULL
;
921 r
= dnssec_algorithm_to_string_alloc(rr
->dnskey
.algorithm
, &alg
);
925 t
= base64mem(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
929 r
= asprintf(&s
, "%s %u %u %s %s",
940 case DNS_TYPE_RRSIG
: {
941 _cleanup_free_
char *alg
= NULL
;
942 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
945 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
947 r
= dnssec_algorithm_to_string_alloc(rr
->rrsig
.algorithm
, &alg
);
951 t
= base64mem(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
955 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
959 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
964 * http://tools.ietf.org/html/rfc3597#section-5 */
966 r
= asprintf(&s
, "%s %s%.*u %s %u %u %s %s %u %s %s",
969 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
972 rr
->rrsig
.original_ttl
,
984 t
= format_types(rr
->nsec
.types
);
988 r
= asprintf(&s
, "%s %s %s",
990 rr
->nsec
.next_domain_name
,
996 case DNS_TYPE_NSEC3
: {
997 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
999 if (rr
->nsec3
.salt_size
> 0) {
1000 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
1005 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
1009 t
= format_types(rr
->nsec3
.types
);
1013 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
1015 rr
->nsec3
.algorithm
,
1017 rr
->nsec3
.iterations
,
1018 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
1028 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
1032 /* Format as documented in RFC 3597, Section 5 */
1033 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.size
, t
);
1043 int dns_resource_record_to_wire_format(DnsResourceRecord
*rr
, bool canonical
) {
1045 DnsPacket packet
= {
1047 .protocol
= DNS_PROTOCOL_DNS
,
1049 .refuse_compression
= true,
1050 .canonical_form
= canonical
,
1058 /* Generates the RR in wire-format, optionally in the
1059 * canonical form as discussed in the DNSSEC RFC 4034, Section
1060 * 6.2. We allocate a throw-away DnsPacket object on the stack
1061 * here, because we need some book-keeping for memory
1062 * management, and can reuse the DnsPacket serializer, that
1063 * can generate the canonical form, too, but also knows label
1064 * compression and suchlike. */
1066 if (rr
->wire_format
&& rr
->wire_format_canonical
== canonical
)
1069 r
= dns_packet_append_rr(&packet
, rr
, &start
, &rds
);
1074 assert(packet
._data
);
1076 free(rr
->wire_format
);
1077 rr
->wire_format
= packet
._data
;
1078 rr
->wire_format_size
= packet
.size
;
1079 rr
->wire_format_rdata_offset
= rds
;
1080 rr
->wire_format_canonical
= canonical
;
1082 packet
._data
= NULL
;
1083 dns_packet_unref(&packet
);
1088 static void dns_resource_record_hash_func(const void *i
, struct siphash
*state
) {
1089 const DnsResourceRecord
*rr
= i
;
1093 dns_resource_key_hash_func(rr
->key
, state
);
1095 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
1098 siphash24_compress(&rr
->srv
.priority
, sizeof(rr
->srv
.priority
), state
);
1099 siphash24_compress(&rr
->srv
.weight
, sizeof(rr
->srv
.weight
), state
);
1100 siphash24_compress(&rr
->srv
.port
, sizeof(rr
->srv
.port
), state
);
1101 dns_name_hash_func(rr
->srv
.name
, state
);
1106 case DNS_TYPE_CNAME
:
1107 case DNS_TYPE_DNAME
:
1108 dns_name_hash_func(rr
->ptr
.name
, state
);
1111 case DNS_TYPE_HINFO
:
1112 string_hash_func(rr
->hinfo
.cpu
, state
);
1113 string_hash_func(rr
->hinfo
.os
, state
);
1117 case DNS_TYPE_SPF
: {
1120 LIST_FOREACH(items
, j
, rr
->txt
.items
) {
1121 siphash24_compress(j
->data
, j
->length
, state
);
1123 /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab"
1124 * followed by "". */
1125 siphash24_compress_byte(0, state
);
1131 siphash24_compress(&rr
->a
.in_addr
, sizeof(rr
->a
.in_addr
), state
);
1135 siphash24_compress(&rr
->aaaa
.in6_addr
, sizeof(rr
->aaaa
.in6_addr
), state
);
1139 dns_name_hash_func(rr
->soa
.mname
, state
);
1140 dns_name_hash_func(rr
->soa
.rname
, state
);
1141 siphash24_compress(&rr
->soa
.serial
, sizeof(rr
->soa
.serial
), state
);
1142 siphash24_compress(&rr
->soa
.refresh
, sizeof(rr
->soa
.refresh
), state
);
1143 siphash24_compress(&rr
->soa
.retry
, sizeof(rr
->soa
.retry
), state
);
1144 siphash24_compress(&rr
->soa
.expire
, sizeof(rr
->soa
.expire
), state
);
1145 siphash24_compress(&rr
->soa
.minimum
, sizeof(rr
->soa
.minimum
), state
);
1149 siphash24_compress(&rr
->mx
.priority
, sizeof(rr
->mx
.priority
), state
);
1150 dns_name_hash_func(rr
->mx
.exchange
, state
);
1154 siphash24_compress(&rr
->loc
.version
, sizeof(rr
->loc
.version
), state
);
1155 siphash24_compress(&rr
->loc
.size
, sizeof(rr
->loc
.size
), state
);
1156 siphash24_compress(&rr
->loc
.horiz_pre
, sizeof(rr
->loc
.horiz_pre
), state
);
1157 siphash24_compress(&rr
->loc
.vert_pre
, sizeof(rr
->loc
.vert_pre
), state
);
1158 siphash24_compress(&rr
->loc
.latitude
, sizeof(rr
->loc
.latitude
), state
);
1159 siphash24_compress(&rr
->loc
.longitude
, sizeof(rr
->loc
.longitude
), state
);
1160 siphash24_compress(&rr
->loc
.altitude
, sizeof(rr
->loc
.altitude
), state
);
1163 case DNS_TYPE_SSHFP
:
1164 siphash24_compress(&rr
->sshfp
.algorithm
, sizeof(rr
->sshfp
.algorithm
), state
);
1165 siphash24_compress(&rr
->sshfp
.fptype
, sizeof(rr
->sshfp
.fptype
), state
);
1166 siphash24_compress(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
, state
);
1169 case DNS_TYPE_DNSKEY
:
1170 siphash24_compress(&rr
->dnskey
.flags
, sizeof(rr
->dnskey
.flags
), state
);
1171 siphash24_compress(&rr
->dnskey
.protocol
, sizeof(rr
->dnskey
.protocol
), state
);
1172 siphash24_compress(&rr
->dnskey
.algorithm
, sizeof(rr
->dnskey
.algorithm
), state
);
1173 siphash24_compress(rr
->dnskey
.key
, rr
->dnskey
.key_size
, state
);
1176 case DNS_TYPE_RRSIG
:
1177 siphash24_compress(&rr
->rrsig
.type_covered
, sizeof(rr
->rrsig
.type_covered
), state
);
1178 siphash24_compress(&rr
->rrsig
.algorithm
, sizeof(rr
->rrsig
.algorithm
), state
);
1179 siphash24_compress(&rr
->rrsig
.labels
, sizeof(rr
->rrsig
.labels
), state
);
1180 siphash24_compress(&rr
->rrsig
.original_ttl
, sizeof(rr
->rrsig
.original_ttl
), state
);
1181 siphash24_compress(&rr
->rrsig
.expiration
, sizeof(rr
->rrsig
.expiration
), state
);
1182 siphash24_compress(&rr
->rrsig
.inception
, sizeof(rr
->rrsig
.inception
), state
);
1183 siphash24_compress(&rr
->rrsig
.key_tag
, sizeof(rr
->rrsig
.key_tag
), state
);
1184 dns_name_hash_func(rr
->rrsig
.signer
, state
);
1185 siphash24_compress(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
, state
);
1189 dns_name_hash_func(rr
->nsec
.next_domain_name
, state
);
1190 /* FIXME: we leave out the type bitmap here. Hash
1191 * would be better if we'd take it into account
1196 siphash24_compress(&rr
->ds
.key_tag
, sizeof(rr
->ds
.key_tag
), state
);
1197 siphash24_compress(&rr
->ds
.algorithm
, sizeof(rr
->ds
.algorithm
), state
);
1198 siphash24_compress(&rr
->ds
.digest_type
, sizeof(rr
->ds
.digest_type
), state
);
1199 siphash24_compress(rr
->ds
.digest
, rr
->ds
.digest_size
, state
);
1202 case DNS_TYPE_NSEC3
:
1203 siphash24_compress(&rr
->nsec3
.algorithm
, sizeof(rr
->nsec3
.algorithm
), state
);
1204 siphash24_compress(&rr
->nsec3
.flags
, sizeof(rr
->nsec3
.flags
), state
);
1205 siphash24_compress(&rr
->nsec3
.iterations
, sizeof(rr
->nsec3
.iterations
), state
);
1206 siphash24_compress(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
, state
);
1207 siphash24_compress(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, state
);
1208 /* FIXME: We leave the bitmaps out */
1212 siphash24_compress(rr
->generic
.data
, rr
->generic
.size
, state
);
1217 static int dns_resource_record_compare_func(const void *a
, const void *b
) {
1218 const DnsResourceRecord
*x
= a
, *y
= b
;
1221 ret
= dns_resource_key_compare_func(x
->key
, y
->key
);
1225 if (dns_resource_record_equal(x
, y
))
1228 /* This is a bit dirty, we don't implement proper odering, but
1229 * the hashtable doesn't need ordering anyway, hence we don't
1231 return x
< y
? -1 : 1;
1234 const struct hash_ops dns_resource_record_hash_ops
= {
1235 .hash
= dns_resource_record_hash_func
,
1236 .compare
= dns_resource_record_compare_func
,
1239 DnsTxtItem
*dns_txt_item_free_all(DnsTxtItem
*i
) {
1248 return dns_txt_item_free_all(n
);
1251 bool dns_txt_item_equal(DnsTxtItem
*a
, DnsTxtItem
*b
) {
1262 if (a
->length
!= b
->length
)
1265 if (memcmp(a
->data
, b
->data
, a
->length
) != 0)
1268 return dns_txt_item_equal(a
->items_next
, b
->items_next
);
1271 static const char* const dnssec_algorithm_table
[_DNSSEC_ALGORITHM_MAX_DEFINED
] = {
1272 /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
1273 [DNSSEC_ALGORITHM_RSAMD5
] = "RSAMD5",
1274 [DNSSEC_ALGORITHM_DH
] = "DH",
1275 [DNSSEC_ALGORITHM_DSA
] = "DSA",
1276 [DNSSEC_ALGORITHM_ECC
] = "ECC",
1277 [DNSSEC_ALGORITHM_RSASHA1
] = "RSASHA1",
1278 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1
] = "DSA-NSEC3-SHA1",
1279 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
] = "RSASHA1-NSEC3-SHA1",
1280 [DNSSEC_ALGORITHM_RSASHA256
] = "RSASHA256",
1281 [DNSSEC_ALGORITHM_RSASHA512
] = "RSASHA512",
1282 [DNSSEC_ALGORITHM_ECC_GOST
] = "ECC-GOST",
1283 [DNSSEC_ALGORITHM_ECDSAP256SHA256
] = "ECDSAP256SHA256",
1284 [DNSSEC_ALGORITHM_ECDSAP384SHA384
] = "ECDSAP384SHA384",
1285 [DNSSEC_ALGORITHM_INDIRECT
] = "INDIRECT",
1286 [DNSSEC_ALGORITHM_PRIVATEDNS
] = "PRIVATEDNS",
1287 [DNSSEC_ALGORITHM_PRIVATEOID
] = "PRIVATEOID",
1289 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm
, int, 255);
1291 static const char* const dnssec_digest_table
[_DNSSEC_DIGEST_MAX_DEFINED
] = {
1292 /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
1293 [DNSSEC_DIGEST_SHA1
] = "SHA-1",
1294 [DNSSEC_DIGEST_SHA256
] = "SHA-256",
1295 [DNSSEC_DIGEST_GOST_R_34_11_94
] = "GOST_R_34.11-94",
1296 [DNSSEC_DIGEST_SHA384
] = "SHA-384",
1298 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest
, int, 255);