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 bool dns_resource_key_reduce(DnsResourceKey
**a
, DnsResourceKey
**b
) {
341 /* Try to replace one RR key by another if they are identical, thus saving a bit of memory. Note that we do
342 * this only for RR keys, not for RRs themselves, as they carry a lot of additional metadata (where they come
343 * from, validity data, and suchlike), and cannot be replaced so easily by other RRs that have the same
344 * superficial data. */
351 /* We refuse merging const keys */
352 if ((*a
)->n_ref
== (unsigned) -1)
354 if ((*b
)->n_ref
== (unsigned) -1)
357 /* Already the same? */
361 /* Are they really identical? */
362 if (dns_resource_key_equal(*a
, *b
) <= 0)
365 /* Keep the one which already has more references. */
366 if ((*a
)->n_ref
> (*b
)->n_ref
) {
367 dns_resource_key_unref(*b
);
368 *b
= dns_resource_key_ref(*a
);
370 dns_resource_key_unref(*a
);
371 *a
= dns_resource_key_ref(*b
);
377 DnsResourceRecord
* dns_resource_record_new(DnsResourceKey
*key
) {
378 DnsResourceRecord
*rr
;
380 rr
= new0(DnsResourceRecord
, 1);
385 rr
->key
= dns_resource_key_ref(key
);
386 rr
->expiry
= USEC_INFINITY
;
387 rr
->n_skip_labels_signer
= rr
->n_skip_labels_source
= (unsigned) -1;
392 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
393 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
395 key
= dns_resource_key_new(class, type
, name
);
399 return dns_resource_record_new(key
);
402 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
406 assert(rr
->n_ref
> 0);
412 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
416 assert(rr
->n_ref
> 0);
424 switch(rr
->key
->type
) {
444 dns_txt_item_free_all(rr
->txt
.items
);
453 free(rr
->mx
.exchange
);
461 free(rr
->sshfp
.fingerprint
);
464 case DNS_TYPE_DNSKEY
:
465 free(rr
->dnskey
.key
);
469 free(rr
->rrsig
.signer
);
470 free(rr
->rrsig
.signature
);
474 free(rr
->nsec
.next_domain_name
);
475 bitmap_free(rr
->nsec
.types
);
479 free(rr
->nsec3
.next_hashed_name
);
480 free(rr
->nsec3
.salt
);
481 bitmap_free(rr
->nsec3
.types
);
490 free(rr
->generic
.data
);
493 free(rr
->wire_format
);
494 dns_resource_key_unref(rr
->key
);
503 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
504 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
505 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
506 _cleanup_free_
char *ptr
= NULL
;
513 r
= dns_name_reverse(family
, address
, &ptr
);
517 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
523 rr
= dns_resource_record_new(key
);
527 rr
->ptr
.name
= strdup(hostname
);
537 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
538 DnsResourceRecord
*rr
;
544 if (family
== AF_INET
) {
546 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
550 rr
->a
.in_addr
= address
->in
;
552 } else if (family
== AF_INET6
) {
554 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
558 rr
->aaaa
.in6_addr
= address
->in6
;
560 return -EAFNOSUPPORT
;
567 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
576 r
= dns_resource_key_equal(a
->key
, b
->key
);
580 if (a
->unparseable
!= b
->unparseable
)
583 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
586 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
590 return a
->srv
.priority
== b
->srv
.priority
&&
591 a
->srv
.weight
== b
->srv
.weight
&&
592 a
->srv
.port
== b
->srv
.port
;
598 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
601 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
602 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
604 case DNS_TYPE_SPF
: /* exactly the same as TXT */
606 return dns_txt_item_equal(a
->txt
.items
, b
->txt
.items
);
609 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
612 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
615 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
618 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
622 return a
->soa
.serial
== b
->soa
.serial
&&
623 a
->soa
.refresh
== b
->soa
.refresh
&&
624 a
->soa
.retry
== b
->soa
.retry
&&
625 a
->soa
.expire
== b
->soa
.expire
&&
626 a
->soa
.minimum
== b
->soa
.minimum
;
629 if (a
->mx
.priority
!= b
->mx
.priority
)
632 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
635 assert(a
->loc
.version
== b
->loc
.version
);
637 return a
->loc
.size
== b
->loc
.size
&&
638 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
639 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
640 a
->loc
.latitude
== b
->loc
.latitude
&&
641 a
->loc
.longitude
== b
->loc
.longitude
&&
642 a
->loc
.altitude
== b
->loc
.altitude
;
645 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
646 a
->ds
.algorithm
== b
->ds
.algorithm
&&
647 a
->ds
.digest_type
== b
->ds
.digest_type
&&
648 a
->ds
.digest_size
== b
->ds
.digest_size
&&
649 memcmp(a
->ds
.digest
, b
->ds
.digest
, a
->ds
.digest_size
) == 0;
652 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
653 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
654 a
->sshfp
.fingerprint_size
== b
->sshfp
.fingerprint_size
&&
655 memcmp(a
->sshfp
.fingerprint
, b
->sshfp
.fingerprint
, a
->sshfp
.fingerprint_size
) == 0;
657 case DNS_TYPE_DNSKEY
:
658 return a
->dnskey
.flags
== b
->dnskey
.flags
&&
659 a
->dnskey
.protocol
== b
->dnskey
.protocol
&&
660 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
661 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
662 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
665 /* do the fast comparisons first */
666 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
667 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
668 a
->rrsig
.labels
!= b
->rrsig
.labels
||
669 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
670 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
671 a
->rrsig
.inception
!= b
->rrsig
.inception
||
672 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
673 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
674 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
677 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
680 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
681 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
684 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
685 a
->nsec3
.flags
== b
->nsec3
.flags
&&
686 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
687 a
->nsec3
.salt_size
== b
->nsec3
.salt_size
&&
688 memcmp(a
->nsec3
.salt
, b
->nsec3
.salt
, a
->nsec3
.salt_size
) == 0 &&
689 memcmp(a
->nsec3
.next_hashed_name
, b
->nsec3
.next_hashed_name
, a
->nsec3
.next_hashed_name_size
) == 0 &&
690 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
693 return a
->generic
.size
== b
->generic
.size
&&
694 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
698 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
699 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
701 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
702 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
704 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
705 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
706 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
707 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
708 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
709 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
711 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
714 (lat
% 60000) / 1000.,
718 (lon
% 60000) / 1000.,
729 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
733 assert(l
> strlen("YYYYMMDDHHmmSS"));
735 if (!gmtime_r(&sec
, &tm
))
738 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
744 static char *format_types(Bitmap
*types
) {
745 _cleanup_strv_free_
char **strv
= NULL
;
746 _cleanup_free_
char *str
= NULL
;
751 BITMAP_FOREACH(type
, types
, i
) {
752 if (dns_type_to_string(type
)) {
753 r
= strv_extend(&strv
, dns_type_to_string(type
));
759 r
= asprintf(&t
, "TYPE%u", type
);
763 r
= strv_consume(&strv
, t
);
769 str
= strv_join(strv
, " ");
773 return strjoin("( ", str
, " )", NULL
);
776 static char *format_txt(DnsTxtItem
*first
) {
781 LIST_FOREACH(items
, i
, first
)
782 c
+= i
->length
* 4 + 3;
784 p
= s
= new(char, c
);
788 LIST_FOREACH(items
, i
, first
) {
796 for (j
= 0; j
< i
->length
; j
++) {
797 if (i
->data
[j
] < ' ' || i
->data
[j
] == '"' || i
->data
[j
] >= 127) {
799 *(p
++) = '0' + (i
->data
[j
] / 100);
800 *(p
++) = '0' + ((i
->data
[j
] / 10) % 10);
801 *(p
++) = '0' + (i
->data
[j
] % 10);
813 const char *dns_resource_record_to_string(DnsResourceRecord
*rr
) {
814 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
821 return rr
->to_string
;
823 r
= dns_resource_key_to_string(rr
->key
, &k
);
827 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
830 r
= asprintf(&s
, "%s %u %u %u %s",
835 strna(rr
->srv
.name
));
844 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
851 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
856 case DNS_TYPE_SPF
: /* exactly the same as TXT */
858 t
= format_txt(rr
->txt
.items
);
862 s
= strjoin(k
, " ", t
, NULL
);
868 _cleanup_free_
char *x
= NULL
;
870 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
874 s
= strjoin(k
, " ", x
, NULL
);
881 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
885 s
= strjoin(k
, " ", t
, NULL
);
891 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
893 strna(rr
->soa
.mname
),
894 strna(rr
->soa
.rname
),
905 r
= asprintf(&s
, "%s %u %s",
914 assert(rr
->loc
.version
== 0);
916 t
= format_location(rr
->loc
.latitude
,
925 s
= strjoin(k
, " ", t
, NULL
);
931 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
935 r
= asprintf(&s
, "%s %u %u %u %s",
946 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
950 r
= asprintf(&s
, "%s %u %u %s",
959 case DNS_TYPE_DNSKEY
: {
960 _cleanup_free_
char *alg
= NULL
;
962 r
= dnssec_algorithm_to_string_alloc(rr
->dnskey
.algorithm
, &alg
);
966 t
= base64mem(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
970 r
= asprintf(&s
, "%s %u %u %s %s",
981 case DNS_TYPE_RRSIG
: {
982 _cleanup_free_
char *alg
= NULL
;
983 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
986 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
988 r
= dnssec_algorithm_to_string_alloc(rr
->rrsig
.algorithm
, &alg
);
992 t
= base64mem(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
996 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
1000 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
1005 * http://tools.ietf.org/html/rfc3597#section-5 */
1007 r
= asprintf(&s
, "%s %s%.*u %s %u %u %s %s %u %s %s",
1010 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
1013 rr
->rrsig
.original_ttl
,
1025 t
= format_types(rr
->nsec
.types
);
1029 r
= asprintf(&s
, "%s %s %s",
1031 rr
->nsec
.next_domain_name
,
1037 case DNS_TYPE_NSEC3
: {
1038 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
1040 if (rr
->nsec3
.salt_size
> 0) {
1041 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
1046 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
1050 t
= format_types(rr
->nsec3
.types
);
1054 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
1056 rr
->nsec3
.algorithm
,
1058 rr
->nsec3
.iterations
,
1059 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
1069 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
1073 /* Format as documented in RFC 3597, Section 5 */
1074 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.size
, t
);
1084 int dns_resource_record_to_wire_format(DnsResourceRecord
*rr
, bool canonical
) {
1086 DnsPacket packet
= {
1088 .protocol
= DNS_PROTOCOL_DNS
,
1090 .refuse_compression
= true,
1091 .canonical_form
= canonical
,
1099 /* Generates the RR in wire-format, optionally in the
1100 * canonical form as discussed in the DNSSEC RFC 4034, Section
1101 * 6.2. We allocate a throw-away DnsPacket object on the stack
1102 * here, because we need some book-keeping for memory
1103 * management, and can reuse the DnsPacket serializer, that
1104 * can generate the canonical form, too, but also knows label
1105 * compression and suchlike. */
1107 if (rr
->wire_format
&& rr
->wire_format_canonical
== canonical
)
1110 r
= dns_packet_append_rr(&packet
, rr
, &start
, &rds
);
1115 assert(packet
._data
);
1117 free(rr
->wire_format
);
1118 rr
->wire_format
= packet
._data
;
1119 rr
->wire_format_size
= packet
.size
;
1120 rr
->wire_format_rdata_offset
= rds
;
1121 rr
->wire_format_canonical
= canonical
;
1123 packet
._data
= NULL
;
1124 dns_packet_unref(&packet
);
1129 int dns_resource_record_signer(DnsResourceRecord
*rr
, const char **ret
) {
1136 /* Returns the RRset's signer, if it is known. */
1138 if (rr
->n_skip_labels_signer
== (unsigned) -1)
1141 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1142 r
= dns_name_skip(n
, rr
->n_skip_labels_signer
, &n
);
1152 int dns_resource_record_source(DnsResourceRecord
*rr
, const char **ret
) {
1159 /* Returns the RRset's synthesizing source, if it is known. */
1161 if (rr
->n_skip_labels_source
== (unsigned) -1)
1164 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1165 r
= dns_name_skip(n
, rr
->n_skip_labels_source
, &n
);
1175 int dns_resource_record_is_signer(DnsResourceRecord
*rr
, const char *zone
) {
1181 r
= dns_resource_record_signer(rr
, &signer
);
1185 return dns_name_equal(zone
, signer
);
1188 int dns_resource_record_is_synthetic(DnsResourceRecord
*rr
) {
1193 /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */
1195 if (rr
->n_skip_labels_source
== (unsigned) -1)
1198 if (rr
->n_skip_labels_source
== 0)
1201 if (rr
->n_skip_labels_source
> 1)
1204 r
= dns_name_startswith(DNS_RESOURCE_KEY_NAME(rr
->key
), "*");
1211 static void dns_resource_record_hash_func(const void *i
, struct siphash
*state
) {
1212 const DnsResourceRecord
*rr
= i
;
1216 dns_resource_key_hash_func(rr
->key
, state
);
1218 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
1221 siphash24_compress(&rr
->srv
.priority
, sizeof(rr
->srv
.priority
), state
);
1222 siphash24_compress(&rr
->srv
.weight
, sizeof(rr
->srv
.weight
), state
);
1223 siphash24_compress(&rr
->srv
.port
, sizeof(rr
->srv
.port
), state
);
1224 dns_name_hash_func(rr
->srv
.name
, state
);
1229 case DNS_TYPE_CNAME
:
1230 case DNS_TYPE_DNAME
:
1231 dns_name_hash_func(rr
->ptr
.name
, state
);
1234 case DNS_TYPE_HINFO
:
1235 string_hash_func(rr
->hinfo
.cpu
, state
);
1236 string_hash_func(rr
->hinfo
.os
, state
);
1240 case DNS_TYPE_SPF
: {
1243 LIST_FOREACH(items
, j
, rr
->txt
.items
) {
1244 siphash24_compress(j
->data
, j
->length
, state
);
1246 /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab"
1247 * followed by "". */
1248 siphash24_compress_byte(0, state
);
1254 siphash24_compress(&rr
->a
.in_addr
, sizeof(rr
->a
.in_addr
), state
);
1258 siphash24_compress(&rr
->aaaa
.in6_addr
, sizeof(rr
->aaaa
.in6_addr
), state
);
1262 dns_name_hash_func(rr
->soa
.mname
, state
);
1263 dns_name_hash_func(rr
->soa
.rname
, state
);
1264 siphash24_compress(&rr
->soa
.serial
, sizeof(rr
->soa
.serial
), state
);
1265 siphash24_compress(&rr
->soa
.refresh
, sizeof(rr
->soa
.refresh
), state
);
1266 siphash24_compress(&rr
->soa
.retry
, sizeof(rr
->soa
.retry
), state
);
1267 siphash24_compress(&rr
->soa
.expire
, sizeof(rr
->soa
.expire
), state
);
1268 siphash24_compress(&rr
->soa
.minimum
, sizeof(rr
->soa
.minimum
), state
);
1272 siphash24_compress(&rr
->mx
.priority
, sizeof(rr
->mx
.priority
), state
);
1273 dns_name_hash_func(rr
->mx
.exchange
, state
);
1277 siphash24_compress(&rr
->loc
.version
, sizeof(rr
->loc
.version
), state
);
1278 siphash24_compress(&rr
->loc
.size
, sizeof(rr
->loc
.size
), state
);
1279 siphash24_compress(&rr
->loc
.horiz_pre
, sizeof(rr
->loc
.horiz_pre
), state
);
1280 siphash24_compress(&rr
->loc
.vert_pre
, sizeof(rr
->loc
.vert_pre
), state
);
1281 siphash24_compress(&rr
->loc
.latitude
, sizeof(rr
->loc
.latitude
), state
);
1282 siphash24_compress(&rr
->loc
.longitude
, sizeof(rr
->loc
.longitude
), state
);
1283 siphash24_compress(&rr
->loc
.altitude
, sizeof(rr
->loc
.altitude
), state
);
1286 case DNS_TYPE_SSHFP
:
1287 siphash24_compress(&rr
->sshfp
.algorithm
, sizeof(rr
->sshfp
.algorithm
), state
);
1288 siphash24_compress(&rr
->sshfp
.fptype
, sizeof(rr
->sshfp
.fptype
), state
);
1289 siphash24_compress(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
, state
);
1292 case DNS_TYPE_DNSKEY
:
1293 siphash24_compress(&rr
->dnskey
.flags
, sizeof(rr
->dnskey
.flags
), state
);
1294 siphash24_compress(&rr
->dnskey
.protocol
, sizeof(rr
->dnskey
.protocol
), state
);
1295 siphash24_compress(&rr
->dnskey
.algorithm
, sizeof(rr
->dnskey
.algorithm
), state
);
1296 siphash24_compress(rr
->dnskey
.key
, rr
->dnskey
.key_size
, state
);
1299 case DNS_TYPE_RRSIG
:
1300 siphash24_compress(&rr
->rrsig
.type_covered
, sizeof(rr
->rrsig
.type_covered
), state
);
1301 siphash24_compress(&rr
->rrsig
.algorithm
, sizeof(rr
->rrsig
.algorithm
), state
);
1302 siphash24_compress(&rr
->rrsig
.labels
, sizeof(rr
->rrsig
.labels
), state
);
1303 siphash24_compress(&rr
->rrsig
.original_ttl
, sizeof(rr
->rrsig
.original_ttl
), state
);
1304 siphash24_compress(&rr
->rrsig
.expiration
, sizeof(rr
->rrsig
.expiration
), state
);
1305 siphash24_compress(&rr
->rrsig
.inception
, sizeof(rr
->rrsig
.inception
), state
);
1306 siphash24_compress(&rr
->rrsig
.key_tag
, sizeof(rr
->rrsig
.key_tag
), state
);
1307 dns_name_hash_func(rr
->rrsig
.signer
, state
);
1308 siphash24_compress(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
, state
);
1312 dns_name_hash_func(rr
->nsec
.next_domain_name
, state
);
1313 /* FIXME: we leave out the type bitmap here. Hash
1314 * would be better if we'd take it into account
1319 siphash24_compress(&rr
->ds
.key_tag
, sizeof(rr
->ds
.key_tag
), state
);
1320 siphash24_compress(&rr
->ds
.algorithm
, sizeof(rr
->ds
.algorithm
), state
);
1321 siphash24_compress(&rr
->ds
.digest_type
, sizeof(rr
->ds
.digest_type
), state
);
1322 siphash24_compress(rr
->ds
.digest
, rr
->ds
.digest_size
, state
);
1325 case DNS_TYPE_NSEC3
:
1326 siphash24_compress(&rr
->nsec3
.algorithm
, sizeof(rr
->nsec3
.algorithm
), state
);
1327 siphash24_compress(&rr
->nsec3
.flags
, sizeof(rr
->nsec3
.flags
), state
);
1328 siphash24_compress(&rr
->nsec3
.iterations
, sizeof(rr
->nsec3
.iterations
), state
);
1329 siphash24_compress(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
, state
);
1330 siphash24_compress(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, state
);
1331 /* FIXME: We leave the bitmaps out */
1335 siphash24_compress(rr
->generic
.data
, rr
->generic
.size
, state
);
1340 static int dns_resource_record_compare_func(const void *a
, const void *b
) {
1341 const DnsResourceRecord
*x
= a
, *y
= b
;
1344 ret
= dns_resource_key_compare_func(x
->key
, y
->key
);
1348 if (dns_resource_record_equal(x
, y
))
1351 /* This is a bit dirty, we don't implement proper odering, but
1352 * the hashtable doesn't need ordering anyway, hence we don't
1354 return x
< y
? -1 : 1;
1357 const struct hash_ops dns_resource_record_hash_ops
= {
1358 .hash
= dns_resource_record_hash_func
,
1359 .compare
= dns_resource_record_compare_func
,
1362 DnsTxtItem
*dns_txt_item_free_all(DnsTxtItem
*i
) {
1371 return dns_txt_item_free_all(n
);
1374 bool dns_txt_item_equal(DnsTxtItem
*a
, DnsTxtItem
*b
) {
1385 if (a
->length
!= b
->length
)
1388 if (memcmp(a
->data
, b
->data
, a
->length
) != 0)
1391 return dns_txt_item_equal(a
->items_next
, b
->items_next
);
1394 static const char* const dnssec_algorithm_table
[_DNSSEC_ALGORITHM_MAX_DEFINED
] = {
1395 /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
1396 [DNSSEC_ALGORITHM_RSAMD5
] = "RSAMD5",
1397 [DNSSEC_ALGORITHM_DH
] = "DH",
1398 [DNSSEC_ALGORITHM_DSA
] = "DSA",
1399 [DNSSEC_ALGORITHM_ECC
] = "ECC",
1400 [DNSSEC_ALGORITHM_RSASHA1
] = "RSASHA1",
1401 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1
] = "DSA-NSEC3-SHA1",
1402 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
] = "RSASHA1-NSEC3-SHA1",
1403 [DNSSEC_ALGORITHM_RSASHA256
] = "RSASHA256",
1404 [DNSSEC_ALGORITHM_RSASHA512
] = "RSASHA512",
1405 [DNSSEC_ALGORITHM_ECC_GOST
] = "ECC-GOST",
1406 [DNSSEC_ALGORITHM_ECDSAP256SHA256
] = "ECDSAP256SHA256",
1407 [DNSSEC_ALGORITHM_ECDSAP384SHA384
] = "ECDSAP384SHA384",
1408 [DNSSEC_ALGORITHM_INDIRECT
] = "INDIRECT",
1409 [DNSSEC_ALGORITHM_PRIVATEDNS
] = "PRIVATEDNS",
1410 [DNSSEC_ALGORITHM_PRIVATEOID
] = "PRIVATEOID",
1412 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm
, int, 255);
1414 static const char* const dnssec_digest_table
[_DNSSEC_DIGEST_MAX_DEFINED
] = {
1415 /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
1416 [DNSSEC_DIGEST_SHA1
] = "SHA-1",
1417 [DNSSEC_DIGEST_SHA256
] = "SHA-256",
1418 [DNSSEC_DIGEST_GOST_R_34_11_94
] = "GOST_R_34.11-94",
1419 [DNSSEC_DIGEST_SHA384
] = "SHA-384",
1421 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest
, int, 255);