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
;
347 rr
->n_skip_labels_signer
= rr
->n_skip_labels_source
= (unsigned) -1;
352 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
353 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
355 key
= dns_resource_key_new(class, type
, name
);
359 return dns_resource_record_new(key
);
362 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
366 assert(rr
->n_ref
> 0);
372 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
376 assert(rr
->n_ref
> 0);
384 switch(rr
->key
->type
) {
404 dns_txt_item_free_all(rr
->txt
.items
);
413 free(rr
->mx
.exchange
);
421 free(rr
->sshfp
.fingerprint
);
424 case DNS_TYPE_DNSKEY
:
425 free(rr
->dnskey
.key
);
429 free(rr
->rrsig
.signer
);
430 free(rr
->rrsig
.signature
);
434 free(rr
->nsec
.next_domain_name
);
435 bitmap_free(rr
->nsec
.types
);
439 free(rr
->nsec3
.next_hashed_name
);
440 free(rr
->nsec3
.salt
);
441 bitmap_free(rr
->nsec3
.types
);
450 free(rr
->generic
.data
);
453 free(rr
->wire_format
);
454 dns_resource_key_unref(rr
->key
);
463 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
464 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
465 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
466 _cleanup_free_
char *ptr
= NULL
;
473 r
= dns_name_reverse(family
, address
, &ptr
);
477 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
483 rr
= dns_resource_record_new(key
);
487 rr
->ptr
.name
= strdup(hostname
);
497 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
498 DnsResourceRecord
*rr
;
504 if (family
== AF_INET
) {
506 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
510 rr
->a
.in_addr
= address
->in
;
512 } else if (family
== AF_INET6
) {
514 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
518 rr
->aaaa
.in6_addr
= address
->in6
;
520 return -EAFNOSUPPORT
;
527 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
536 r
= dns_resource_key_equal(a
->key
, b
->key
);
540 if (a
->unparseable
!= b
->unparseable
)
543 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
546 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
550 return a
->srv
.priority
== b
->srv
.priority
&&
551 a
->srv
.weight
== b
->srv
.weight
&&
552 a
->srv
.port
== b
->srv
.port
;
558 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
561 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
562 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
564 case DNS_TYPE_SPF
: /* exactly the same as TXT */
566 return dns_txt_item_equal(a
->txt
.items
, b
->txt
.items
);
569 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
572 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
575 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
578 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
582 return a
->soa
.serial
== b
->soa
.serial
&&
583 a
->soa
.refresh
== b
->soa
.refresh
&&
584 a
->soa
.retry
== b
->soa
.retry
&&
585 a
->soa
.expire
== b
->soa
.expire
&&
586 a
->soa
.minimum
== b
->soa
.minimum
;
589 if (a
->mx
.priority
!= b
->mx
.priority
)
592 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
595 assert(a
->loc
.version
== b
->loc
.version
);
597 return a
->loc
.size
== b
->loc
.size
&&
598 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
599 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
600 a
->loc
.latitude
== b
->loc
.latitude
&&
601 a
->loc
.longitude
== b
->loc
.longitude
&&
602 a
->loc
.altitude
== b
->loc
.altitude
;
605 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
606 a
->ds
.algorithm
== b
->ds
.algorithm
&&
607 a
->ds
.digest_type
== b
->ds
.digest_type
&&
608 a
->ds
.digest_size
== b
->ds
.digest_size
&&
609 memcmp(a
->ds
.digest
, b
->ds
.digest
, a
->ds
.digest_size
) == 0;
612 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
613 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
614 a
->sshfp
.fingerprint_size
== b
->sshfp
.fingerprint_size
&&
615 memcmp(a
->sshfp
.fingerprint
, b
->sshfp
.fingerprint
, a
->sshfp
.fingerprint_size
) == 0;
617 case DNS_TYPE_DNSKEY
:
618 return a
->dnskey
.flags
== b
->dnskey
.flags
&&
619 a
->dnskey
.protocol
== b
->dnskey
.protocol
&&
620 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
621 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
622 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
625 /* do the fast comparisons first */
626 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
627 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
628 a
->rrsig
.labels
!= b
->rrsig
.labels
||
629 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
630 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
631 a
->rrsig
.inception
!= b
->rrsig
.inception
||
632 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
633 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
634 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
637 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
640 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
641 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
644 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
645 a
->nsec3
.flags
== b
->nsec3
.flags
&&
646 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
647 a
->nsec3
.salt_size
== b
->nsec3
.salt_size
&&
648 memcmp(a
->nsec3
.salt
, b
->nsec3
.salt
, a
->nsec3
.salt_size
) == 0 &&
649 memcmp(a
->nsec3
.next_hashed_name
, b
->nsec3
.next_hashed_name
, a
->nsec3
.next_hashed_name_size
) == 0 &&
650 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
653 return a
->generic
.size
== b
->generic
.size
&&
654 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
658 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
659 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
661 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
662 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
664 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
665 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
666 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
667 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
668 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
669 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
671 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
674 (lat
% 60000) / 1000.,
678 (lon
% 60000) / 1000.,
689 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
693 assert(l
> strlen("YYYYMMDDHHmmSS"));
695 if (!gmtime_r(&sec
, &tm
))
698 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
704 static char *format_types(Bitmap
*types
) {
705 _cleanup_strv_free_
char **strv
= NULL
;
706 _cleanup_free_
char *str
= NULL
;
711 BITMAP_FOREACH(type
, types
, i
) {
712 if (dns_type_to_string(type
)) {
713 r
= strv_extend(&strv
, dns_type_to_string(type
));
719 r
= asprintf(&t
, "TYPE%u", type
);
723 r
= strv_consume(&strv
, t
);
729 str
= strv_join(strv
, " ");
733 return strjoin("( ", str
, " )", NULL
);
736 static char *format_txt(DnsTxtItem
*first
) {
741 LIST_FOREACH(items
, i
, first
)
742 c
+= i
->length
* 4 + 3;
744 p
= s
= new(char, c
);
748 LIST_FOREACH(items
, i
, first
) {
756 for (j
= 0; j
< i
->length
; j
++) {
757 if (i
->data
[j
] < ' ' || i
->data
[j
] == '"' || i
->data
[j
] >= 127) {
759 *(p
++) = '0' + (i
->data
[j
] / 100);
760 *(p
++) = '0' + ((i
->data
[j
] / 10) % 10);
761 *(p
++) = '0' + (i
->data
[j
] % 10);
773 const char *dns_resource_record_to_string(DnsResourceRecord
*rr
) {
774 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
781 return rr
->to_string
;
783 r
= dns_resource_key_to_string(rr
->key
, &k
);
787 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
790 r
= asprintf(&s
, "%s %u %u %u %s",
795 strna(rr
->srv
.name
));
804 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
811 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
816 case DNS_TYPE_SPF
: /* exactly the same as TXT */
818 t
= format_txt(rr
->txt
.items
);
822 s
= strjoin(k
, " ", t
, NULL
);
828 _cleanup_free_
char *x
= NULL
;
830 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
834 s
= strjoin(k
, " ", x
, NULL
);
841 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
845 s
= strjoin(k
, " ", t
, NULL
);
851 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
853 strna(rr
->soa
.mname
),
854 strna(rr
->soa
.rname
),
865 r
= asprintf(&s
, "%s %u %s",
874 assert(rr
->loc
.version
== 0);
876 t
= format_location(rr
->loc
.latitude
,
885 s
= strjoin(k
, " ", t
, NULL
);
891 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
895 r
= asprintf(&s
, "%s %u %u %u %s",
906 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
910 r
= asprintf(&s
, "%s %u %u %s",
919 case DNS_TYPE_DNSKEY
: {
920 _cleanup_free_
char *alg
= NULL
;
922 r
= dnssec_algorithm_to_string_alloc(rr
->dnskey
.algorithm
, &alg
);
926 t
= base64mem(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
930 r
= asprintf(&s
, "%s %u %u %s %s",
941 case DNS_TYPE_RRSIG
: {
942 _cleanup_free_
char *alg
= NULL
;
943 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
946 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
948 r
= dnssec_algorithm_to_string_alloc(rr
->rrsig
.algorithm
, &alg
);
952 t
= base64mem(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
956 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
960 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
965 * http://tools.ietf.org/html/rfc3597#section-5 */
967 r
= asprintf(&s
, "%s %s%.*u %s %u %u %s %s %u %s %s",
970 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
973 rr
->rrsig
.original_ttl
,
985 t
= format_types(rr
->nsec
.types
);
989 r
= asprintf(&s
, "%s %s %s",
991 rr
->nsec
.next_domain_name
,
997 case DNS_TYPE_NSEC3
: {
998 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
1000 if (rr
->nsec3
.salt_size
> 0) {
1001 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
1006 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
1010 t
= format_types(rr
->nsec3
.types
);
1014 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
1016 rr
->nsec3
.algorithm
,
1018 rr
->nsec3
.iterations
,
1019 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
1029 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
1033 /* Format as documented in RFC 3597, Section 5 */
1034 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.size
, t
);
1044 int dns_resource_record_to_wire_format(DnsResourceRecord
*rr
, bool canonical
) {
1046 DnsPacket packet
= {
1048 .protocol
= DNS_PROTOCOL_DNS
,
1050 .refuse_compression
= true,
1051 .canonical_form
= canonical
,
1059 /* Generates the RR in wire-format, optionally in the
1060 * canonical form as discussed in the DNSSEC RFC 4034, Section
1061 * 6.2. We allocate a throw-away DnsPacket object on the stack
1062 * here, because we need some book-keeping for memory
1063 * management, and can reuse the DnsPacket serializer, that
1064 * can generate the canonical form, too, but also knows label
1065 * compression and suchlike. */
1067 if (rr
->wire_format
&& rr
->wire_format_canonical
== canonical
)
1070 r
= dns_packet_append_rr(&packet
, rr
, &start
, &rds
);
1075 assert(packet
._data
);
1077 free(rr
->wire_format
);
1078 rr
->wire_format
= packet
._data
;
1079 rr
->wire_format_size
= packet
.size
;
1080 rr
->wire_format_rdata_offset
= rds
;
1081 rr
->wire_format_canonical
= canonical
;
1083 packet
._data
= NULL
;
1084 dns_packet_unref(&packet
);
1089 int dns_resource_record_signer(DnsResourceRecord
*rr
, const char **ret
) {
1096 /* Returns the RRset's signer, if it is known. */
1098 if (rr
->n_skip_labels_signer
== (unsigned) -1)
1101 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1102 r
= dns_name_skip(n
, rr
->n_skip_labels_signer
, &n
);
1112 int dns_resource_record_source(DnsResourceRecord
*rr
, const char **ret
) {
1119 /* Returns the RRset's synthesizing source, if it is known. */
1121 if (rr
->n_skip_labels_source
== (unsigned) -1)
1124 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1125 r
= dns_name_skip(n
, rr
->n_skip_labels_source
, &n
);
1135 int dns_resource_record_is_signer(DnsResourceRecord
*rr
, const char *zone
) {
1141 r
= dns_resource_record_signer(rr
, &signer
);
1145 return dns_name_equal(zone
, signer
);
1148 int dns_resource_record_is_synthetic(DnsResourceRecord
*rr
) {
1153 /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */
1155 if (rr
->n_skip_labels_source
== (unsigned) -1)
1158 if (rr
->n_skip_labels_source
== 0)
1161 if (rr
->n_skip_labels_source
> 1)
1164 r
= dns_name_startswith(DNS_RESOURCE_KEY_NAME(rr
->key
), "*");
1171 static void dns_resource_record_hash_func(const void *i
, struct siphash
*state
) {
1172 const DnsResourceRecord
*rr
= i
;
1176 dns_resource_key_hash_func(rr
->key
, state
);
1178 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
1181 siphash24_compress(&rr
->srv
.priority
, sizeof(rr
->srv
.priority
), state
);
1182 siphash24_compress(&rr
->srv
.weight
, sizeof(rr
->srv
.weight
), state
);
1183 siphash24_compress(&rr
->srv
.port
, sizeof(rr
->srv
.port
), state
);
1184 dns_name_hash_func(rr
->srv
.name
, state
);
1189 case DNS_TYPE_CNAME
:
1190 case DNS_TYPE_DNAME
:
1191 dns_name_hash_func(rr
->ptr
.name
, state
);
1194 case DNS_TYPE_HINFO
:
1195 string_hash_func(rr
->hinfo
.cpu
, state
);
1196 string_hash_func(rr
->hinfo
.os
, state
);
1200 case DNS_TYPE_SPF
: {
1203 LIST_FOREACH(items
, j
, rr
->txt
.items
) {
1204 siphash24_compress(j
->data
, j
->length
, state
);
1206 /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab"
1207 * followed by "". */
1208 siphash24_compress_byte(0, state
);
1214 siphash24_compress(&rr
->a
.in_addr
, sizeof(rr
->a
.in_addr
), state
);
1218 siphash24_compress(&rr
->aaaa
.in6_addr
, sizeof(rr
->aaaa
.in6_addr
), state
);
1222 dns_name_hash_func(rr
->soa
.mname
, state
);
1223 dns_name_hash_func(rr
->soa
.rname
, state
);
1224 siphash24_compress(&rr
->soa
.serial
, sizeof(rr
->soa
.serial
), state
);
1225 siphash24_compress(&rr
->soa
.refresh
, sizeof(rr
->soa
.refresh
), state
);
1226 siphash24_compress(&rr
->soa
.retry
, sizeof(rr
->soa
.retry
), state
);
1227 siphash24_compress(&rr
->soa
.expire
, sizeof(rr
->soa
.expire
), state
);
1228 siphash24_compress(&rr
->soa
.minimum
, sizeof(rr
->soa
.minimum
), state
);
1232 siphash24_compress(&rr
->mx
.priority
, sizeof(rr
->mx
.priority
), state
);
1233 dns_name_hash_func(rr
->mx
.exchange
, state
);
1237 siphash24_compress(&rr
->loc
.version
, sizeof(rr
->loc
.version
), state
);
1238 siphash24_compress(&rr
->loc
.size
, sizeof(rr
->loc
.size
), state
);
1239 siphash24_compress(&rr
->loc
.horiz_pre
, sizeof(rr
->loc
.horiz_pre
), state
);
1240 siphash24_compress(&rr
->loc
.vert_pre
, sizeof(rr
->loc
.vert_pre
), state
);
1241 siphash24_compress(&rr
->loc
.latitude
, sizeof(rr
->loc
.latitude
), state
);
1242 siphash24_compress(&rr
->loc
.longitude
, sizeof(rr
->loc
.longitude
), state
);
1243 siphash24_compress(&rr
->loc
.altitude
, sizeof(rr
->loc
.altitude
), state
);
1246 case DNS_TYPE_SSHFP
:
1247 siphash24_compress(&rr
->sshfp
.algorithm
, sizeof(rr
->sshfp
.algorithm
), state
);
1248 siphash24_compress(&rr
->sshfp
.fptype
, sizeof(rr
->sshfp
.fptype
), state
);
1249 siphash24_compress(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
, state
);
1252 case DNS_TYPE_DNSKEY
:
1253 siphash24_compress(&rr
->dnskey
.flags
, sizeof(rr
->dnskey
.flags
), state
);
1254 siphash24_compress(&rr
->dnskey
.protocol
, sizeof(rr
->dnskey
.protocol
), state
);
1255 siphash24_compress(&rr
->dnskey
.algorithm
, sizeof(rr
->dnskey
.algorithm
), state
);
1256 siphash24_compress(rr
->dnskey
.key
, rr
->dnskey
.key_size
, state
);
1259 case DNS_TYPE_RRSIG
:
1260 siphash24_compress(&rr
->rrsig
.type_covered
, sizeof(rr
->rrsig
.type_covered
), state
);
1261 siphash24_compress(&rr
->rrsig
.algorithm
, sizeof(rr
->rrsig
.algorithm
), state
);
1262 siphash24_compress(&rr
->rrsig
.labels
, sizeof(rr
->rrsig
.labels
), state
);
1263 siphash24_compress(&rr
->rrsig
.original_ttl
, sizeof(rr
->rrsig
.original_ttl
), state
);
1264 siphash24_compress(&rr
->rrsig
.expiration
, sizeof(rr
->rrsig
.expiration
), state
);
1265 siphash24_compress(&rr
->rrsig
.inception
, sizeof(rr
->rrsig
.inception
), state
);
1266 siphash24_compress(&rr
->rrsig
.key_tag
, sizeof(rr
->rrsig
.key_tag
), state
);
1267 dns_name_hash_func(rr
->rrsig
.signer
, state
);
1268 siphash24_compress(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
, state
);
1272 dns_name_hash_func(rr
->nsec
.next_domain_name
, state
);
1273 /* FIXME: we leave out the type bitmap here. Hash
1274 * would be better if we'd take it into account
1279 siphash24_compress(&rr
->ds
.key_tag
, sizeof(rr
->ds
.key_tag
), state
);
1280 siphash24_compress(&rr
->ds
.algorithm
, sizeof(rr
->ds
.algorithm
), state
);
1281 siphash24_compress(&rr
->ds
.digest_type
, sizeof(rr
->ds
.digest_type
), state
);
1282 siphash24_compress(rr
->ds
.digest
, rr
->ds
.digest_size
, state
);
1285 case DNS_TYPE_NSEC3
:
1286 siphash24_compress(&rr
->nsec3
.algorithm
, sizeof(rr
->nsec3
.algorithm
), state
);
1287 siphash24_compress(&rr
->nsec3
.flags
, sizeof(rr
->nsec3
.flags
), state
);
1288 siphash24_compress(&rr
->nsec3
.iterations
, sizeof(rr
->nsec3
.iterations
), state
);
1289 siphash24_compress(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
, state
);
1290 siphash24_compress(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, state
);
1291 /* FIXME: We leave the bitmaps out */
1295 siphash24_compress(rr
->generic
.data
, rr
->generic
.size
, state
);
1300 static int dns_resource_record_compare_func(const void *a
, const void *b
) {
1301 const DnsResourceRecord
*x
= a
, *y
= b
;
1304 ret
= dns_resource_key_compare_func(x
->key
, y
->key
);
1308 if (dns_resource_record_equal(x
, y
))
1311 /* This is a bit dirty, we don't implement proper odering, but
1312 * the hashtable doesn't need ordering anyway, hence we don't
1314 return x
< y
? -1 : 1;
1317 const struct hash_ops dns_resource_record_hash_ops
= {
1318 .hash
= dns_resource_record_hash_func
,
1319 .compare
= dns_resource_record_compare_func
,
1322 DnsTxtItem
*dns_txt_item_free_all(DnsTxtItem
*i
) {
1331 return dns_txt_item_free_all(n
);
1334 bool dns_txt_item_equal(DnsTxtItem
*a
, DnsTxtItem
*b
) {
1345 if (a
->length
!= b
->length
)
1348 if (memcmp(a
->data
, b
->data
, a
->length
) != 0)
1351 return dns_txt_item_equal(a
->items_next
, b
->items_next
);
1354 static const char* const dnssec_algorithm_table
[_DNSSEC_ALGORITHM_MAX_DEFINED
] = {
1355 /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
1356 [DNSSEC_ALGORITHM_RSAMD5
] = "RSAMD5",
1357 [DNSSEC_ALGORITHM_DH
] = "DH",
1358 [DNSSEC_ALGORITHM_DSA
] = "DSA",
1359 [DNSSEC_ALGORITHM_ECC
] = "ECC",
1360 [DNSSEC_ALGORITHM_RSASHA1
] = "RSASHA1",
1361 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1
] = "DSA-NSEC3-SHA1",
1362 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
] = "RSASHA1-NSEC3-SHA1",
1363 [DNSSEC_ALGORITHM_RSASHA256
] = "RSASHA256",
1364 [DNSSEC_ALGORITHM_RSASHA512
] = "RSASHA512",
1365 [DNSSEC_ALGORITHM_ECC_GOST
] = "ECC-GOST",
1366 [DNSSEC_ALGORITHM_ECDSAP256SHA256
] = "ECDSAP256SHA256",
1367 [DNSSEC_ALGORITHM_ECDSAP384SHA384
] = "ECDSAP384SHA384",
1368 [DNSSEC_ALGORITHM_INDIRECT
] = "INDIRECT",
1369 [DNSSEC_ALGORITHM_PRIVATEDNS
] = "PRIVATEDNS",
1370 [DNSSEC_ALGORITHM_PRIVATEOID
] = "PRIVATEOID",
1372 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm
, int, 255);
1374 static const char* const dnssec_digest_table
[_DNSSEC_DIGEST_MAX_DEFINED
] = {
1375 /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
1376 [DNSSEC_DIGEST_SHA1
] = "SHA-1",
1377 [DNSSEC_DIGEST_SHA256
] = "SHA-256",
1378 [DNSSEC_DIGEST_GOST_R_34_11_94
] = "GOST_R_34.11-94",
1379 [DNSSEC_DIGEST_SHA384
] = "SHA-384",
1381 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest
, int, 255);