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"
33 #include "terminal-util.h"
35 DnsResourceKey
* dns_resource_key_new(uint16_t class, uint16_t type
, const char *name
) {
42 k
= malloc0(sizeof(DnsResourceKey
) + l
+ 1);
50 strcpy((char*) k
+ sizeof(DnsResourceKey
), name
);
55 DnsResourceKey
* dns_resource_key_new_redirect(const DnsResourceKey
*key
, const DnsResourceRecord
*cname
) {
61 assert(IN_SET(cname
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
));
63 if (cname
->key
->type
== DNS_TYPE_CNAME
)
64 return dns_resource_key_new(key
->class, key
->type
, cname
->cname
.name
);
67 char *destination
= NULL
;
69 r
= dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(cname
->key
), cname
->dname
.name
, &destination
);
73 return dns_resource_key_ref((DnsResourceKey
*) key
);
75 k
= dns_resource_key_new_consume(key
->class, key
->type
, destination
);
85 int dns_resource_key_new_append_suffix(DnsResourceKey
**ret
, DnsResourceKey
*key
, char *name
) {
86 DnsResourceKey
*new_key
;
94 if (dns_name_is_root(name
)) {
95 *ret
= dns_resource_key_ref(key
);
99 r
= dns_name_concat(DNS_RESOURCE_KEY_NAME(key
), name
, &joined
);
103 new_key
= dns_resource_key_new_consume(key
->class, key
->type
, joined
);
113 DnsResourceKey
* dns_resource_key_new_consume(uint16_t class, uint16_t type
, char *name
) {
118 k
= new0(DnsResourceKey
, 1);
130 DnsResourceKey
* dns_resource_key_ref(DnsResourceKey
*k
) {
135 /* Static/const keys created with DNS_RESOURCE_KEY_CONST will
136 * set this to -1, they should not be reffed/unreffed */
137 assert(k
->n_ref
!= (unsigned) -1);
139 assert(k
->n_ref
> 0);
145 DnsResourceKey
* dns_resource_key_unref(DnsResourceKey
*k
) {
149 assert(k
->n_ref
!= (unsigned) -1);
150 assert(k
->n_ref
> 0);
161 bool dns_resource_key_is_address(const DnsResourceKey
*key
) {
164 /* Check if this is an A or AAAA resource key */
166 return key
->class == DNS_CLASS_IN
&& IN_SET(key
->type
, DNS_TYPE_A
, DNS_TYPE_AAAA
);
169 int dns_resource_key_equal(const DnsResourceKey
*a
, const DnsResourceKey
*b
) {
175 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(a
), DNS_RESOURCE_KEY_NAME(b
));
179 if (a
->class != b
->class)
182 if (a
->type
!= b
->type
)
188 int dns_resource_key_match_rr(const DnsResourceKey
*key
, DnsResourceRecord
*rr
, const char *search_domain
) {
197 /* Checks if an rr matches the specified key. If a search
198 * domain is specified, it will also be checked if the key
199 * with the search domain suffixed might match the RR. */
201 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
204 if (rr
->key
->type
!= key
->type
&& key
->type
!= DNS_TYPE_ANY
)
207 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
212 _cleanup_free_
char *joined
= NULL
;
214 r
= dns_name_concat(DNS_RESOURCE_KEY_NAME(key
), search_domain
, &joined
);
218 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), joined
);
224 int dns_resource_key_match_cname_or_dname(const DnsResourceKey
*key
, const DnsResourceKey
*cname
, const char *search_domain
) {
230 if (cname
->class != key
->class && key
->class != DNS_CLASS_ANY
)
233 if (cname
->type
== DNS_TYPE_CNAME
)
234 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(cname
));
235 else if (cname
->type
== DNS_TYPE_DNAME
)
236 r
= dns_name_endswith(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(cname
));
244 _cleanup_free_
char *joined
= NULL
;
246 r
= dns_name_concat(DNS_RESOURCE_KEY_NAME(key
), search_domain
, &joined
);
250 if (cname
->type
== DNS_TYPE_CNAME
)
251 return dns_name_equal(joined
, DNS_RESOURCE_KEY_NAME(cname
));
252 else if (cname
->type
== DNS_TYPE_DNAME
)
253 return dns_name_endswith(joined
, DNS_RESOURCE_KEY_NAME(cname
));
259 int dns_resource_key_match_soa(const DnsResourceKey
*key
, const DnsResourceKey
*soa
) {
263 /* Checks whether 'soa' is a SOA record for the specified key. */
265 if (soa
->class != key
->class)
268 if (soa
->type
!= DNS_TYPE_SOA
)
271 return dns_name_endswith(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(soa
));
274 static void dns_resource_key_hash_func(const void *i
, struct siphash
*state
) {
275 const DnsResourceKey
*k
= i
;
279 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k
), state
);
280 siphash24_compress(&k
->class, sizeof(k
->class), state
);
281 siphash24_compress(&k
->type
, sizeof(k
->type
), state
);
284 static int dns_resource_key_compare_func(const void *a
, const void *b
) {
285 const DnsResourceKey
*x
= a
, *y
= b
;
288 ret
= dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x
), DNS_RESOURCE_KEY_NAME(y
));
292 if (x
->type
< y
->type
)
294 if (x
->type
> y
->type
)
297 if (x
->class < y
->class)
299 if (x
->class > y
->class)
305 const struct hash_ops dns_resource_key_hash_ops
= {
306 .hash
= dns_resource_key_hash_func
,
307 .compare
= dns_resource_key_compare_func
310 int dns_resource_key_to_string(const DnsResourceKey
*key
, char **ret
) {
311 char cbuf
[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf
[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
312 const char *c
, *t
, *n
;
315 /* If we cannot convert the CLASS/TYPE into a known string,
316 use the format recommended by RFC 3597, Section 5. */
318 c
= dns_class_to_string(key
->class);
320 sprintf(cbuf
, "CLASS%u", key
->class);
324 t
= dns_type_to_string(key
->type
);
326 sprintf(tbuf
, "TYPE%u", key
->type
);
330 n
= DNS_RESOURCE_KEY_NAME(key
);
331 if (asprintf(&s
, "%s%s %s %-5s", n
, endswith(n
, ".") ? "" : ".", c
, t
) < 0)
338 bool dns_resource_key_reduce(DnsResourceKey
**a
, DnsResourceKey
**b
) {
342 /* Try to replace one RR key by another if they are identical, thus saving a bit of memory. Note that we do
343 * this only for RR keys, not for RRs themselves, as they carry a lot of additional metadata (where they come
344 * from, validity data, and suchlike), and cannot be replaced so easily by other RRs that have the same
345 * superficial data. */
352 /* We refuse merging const keys */
353 if ((*a
)->n_ref
== (unsigned) -1)
355 if ((*b
)->n_ref
== (unsigned) -1)
358 /* Already the same? */
362 /* Are they really identical? */
363 if (dns_resource_key_equal(*a
, *b
) <= 0)
366 /* Keep the one which already has more references. */
367 if ((*a
)->n_ref
> (*b
)->n_ref
) {
368 dns_resource_key_unref(*b
);
369 *b
= dns_resource_key_ref(*a
);
371 dns_resource_key_unref(*a
);
372 *a
= dns_resource_key_ref(*b
);
378 DnsResourceRecord
* dns_resource_record_new(DnsResourceKey
*key
) {
379 DnsResourceRecord
*rr
;
381 rr
= new0(DnsResourceRecord
, 1);
386 rr
->key
= dns_resource_key_ref(key
);
387 rr
->expiry
= USEC_INFINITY
;
388 rr
->n_skip_labels_signer
= rr
->n_skip_labels_source
= (unsigned) -1;
393 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
394 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
396 key
= dns_resource_key_new(class, type
, name
);
400 return dns_resource_record_new(key
);
403 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
407 assert(rr
->n_ref
> 0);
413 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
417 assert(rr
->n_ref
> 0);
425 switch(rr
->key
->type
) {
445 dns_txt_item_free_all(rr
->txt
.items
);
454 free(rr
->mx
.exchange
);
462 free(rr
->sshfp
.fingerprint
);
465 case DNS_TYPE_DNSKEY
:
466 free(rr
->dnskey
.key
);
470 free(rr
->rrsig
.signer
);
471 free(rr
->rrsig
.signature
);
475 free(rr
->nsec
.next_domain_name
);
476 bitmap_free(rr
->nsec
.types
);
480 free(rr
->nsec3
.next_hashed_name
);
481 free(rr
->nsec3
.salt
);
482 bitmap_free(rr
->nsec3
.types
);
491 free(rr
->generic
.data
);
494 free(rr
->wire_format
);
495 dns_resource_key_unref(rr
->key
);
504 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
505 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
506 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
507 _cleanup_free_
char *ptr
= NULL
;
514 r
= dns_name_reverse(family
, address
, &ptr
);
518 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
524 rr
= dns_resource_record_new(key
);
528 rr
->ptr
.name
= strdup(hostname
);
538 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
539 DnsResourceRecord
*rr
;
545 if (family
== AF_INET
) {
547 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
551 rr
->a
.in_addr
= address
->in
;
553 } else if (family
== AF_INET6
) {
555 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
559 rr
->aaaa
.in6_addr
= address
->in6
;
561 return -EAFNOSUPPORT
;
568 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
577 r
= dns_resource_key_equal(a
->key
, b
->key
);
581 if (a
->unparseable
!= b
->unparseable
)
584 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
587 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
591 return a
->srv
.priority
== b
->srv
.priority
&&
592 a
->srv
.weight
== b
->srv
.weight
&&
593 a
->srv
.port
== b
->srv
.port
;
599 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
602 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
603 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
605 case DNS_TYPE_SPF
: /* exactly the same as TXT */
607 return dns_txt_item_equal(a
->txt
.items
, b
->txt
.items
);
610 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
613 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
616 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
619 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
623 return a
->soa
.serial
== b
->soa
.serial
&&
624 a
->soa
.refresh
== b
->soa
.refresh
&&
625 a
->soa
.retry
== b
->soa
.retry
&&
626 a
->soa
.expire
== b
->soa
.expire
&&
627 a
->soa
.minimum
== b
->soa
.minimum
;
630 if (a
->mx
.priority
!= b
->mx
.priority
)
633 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
636 assert(a
->loc
.version
== b
->loc
.version
);
638 return a
->loc
.size
== b
->loc
.size
&&
639 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
640 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
641 a
->loc
.latitude
== b
->loc
.latitude
&&
642 a
->loc
.longitude
== b
->loc
.longitude
&&
643 a
->loc
.altitude
== b
->loc
.altitude
;
646 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
647 a
->ds
.algorithm
== b
->ds
.algorithm
&&
648 a
->ds
.digest_type
== b
->ds
.digest_type
&&
649 a
->ds
.digest_size
== b
->ds
.digest_size
&&
650 memcmp(a
->ds
.digest
, b
->ds
.digest
, a
->ds
.digest_size
) == 0;
653 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
654 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
655 a
->sshfp
.fingerprint_size
== b
->sshfp
.fingerprint_size
&&
656 memcmp(a
->sshfp
.fingerprint
, b
->sshfp
.fingerprint
, a
->sshfp
.fingerprint_size
) == 0;
658 case DNS_TYPE_DNSKEY
:
659 return a
->dnskey
.flags
== b
->dnskey
.flags
&&
660 a
->dnskey
.protocol
== b
->dnskey
.protocol
&&
661 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
662 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
663 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
666 /* do the fast comparisons first */
667 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
668 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
669 a
->rrsig
.labels
!= b
->rrsig
.labels
||
670 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
671 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
672 a
->rrsig
.inception
!= b
->rrsig
.inception
||
673 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
674 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
675 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
678 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
681 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
682 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
685 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
686 a
->nsec3
.flags
== b
->nsec3
.flags
&&
687 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
688 a
->nsec3
.salt_size
== b
->nsec3
.salt_size
&&
689 memcmp(a
->nsec3
.salt
, b
->nsec3
.salt
, a
->nsec3
.salt_size
) == 0 &&
690 memcmp(a
->nsec3
.next_hashed_name
, b
->nsec3
.next_hashed_name
, a
->nsec3
.next_hashed_name_size
) == 0 &&
691 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
694 return a
->generic
.size
== b
->generic
.size
&&
695 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
699 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
700 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
702 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
703 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
705 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
706 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
707 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
708 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
709 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
710 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
712 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
715 (lat
% 60000) / 1000.,
719 (lon
% 60000) / 1000.,
730 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
734 assert(l
> strlen("YYYYMMDDHHmmSS"));
736 if (!gmtime_r(&sec
, &tm
))
739 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
745 static char *format_types(Bitmap
*types
) {
746 _cleanup_strv_free_
char **strv
= NULL
;
747 _cleanup_free_
char *str
= NULL
;
752 BITMAP_FOREACH(type
, types
, i
) {
753 if (dns_type_to_string(type
)) {
754 r
= strv_extend(&strv
, dns_type_to_string(type
));
760 r
= asprintf(&t
, "TYPE%u", type
);
764 r
= strv_consume(&strv
, t
);
770 str
= strv_join(strv
, " ");
774 return strjoin("( ", str
, " )", NULL
);
777 static char *format_txt(DnsTxtItem
*first
) {
782 LIST_FOREACH(items
, i
, first
)
783 c
+= i
->length
* 4 + 3;
785 p
= s
= new(char, c
);
789 LIST_FOREACH(items
, i
, first
) {
797 for (j
= 0; j
< i
->length
; j
++) {
798 if (i
->data
[j
] < ' ' || i
->data
[j
] == '"' || i
->data
[j
] >= 127) {
800 *(p
++) = '0' + (i
->data
[j
] / 100);
801 *(p
++) = '0' + ((i
->data
[j
] / 10) % 10);
802 *(p
++) = '0' + (i
->data
[j
] % 10);
814 const char *dns_resource_record_to_string(DnsResourceRecord
*rr
) {
815 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
822 return rr
->to_string
;
824 r
= dns_resource_key_to_string(rr
->key
, &k
);
828 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
831 r
= asprintf(&s
, "%s %u %u %u %s",
836 strna(rr
->srv
.name
));
845 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
852 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
857 case DNS_TYPE_SPF
: /* exactly the same as TXT */
859 t
= format_txt(rr
->txt
.items
);
863 s
= strjoin(k
, " ", t
, NULL
);
869 _cleanup_free_
char *x
= NULL
;
871 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
875 s
= strjoin(k
, " ", x
, NULL
);
882 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
886 s
= strjoin(k
, " ", t
, NULL
);
892 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
894 strna(rr
->soa
.mname
),
895 strna(rr
->soa
.rname
),
906 r
= asprintf(&s
, "%s %u %s",
915 assert(rr
->loc
.version
== 0);
917 t
= format_location(rr
->loc
.latitude
,
926 s
= strjoin(k
, " ", t
, NULL
);
932 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
936 r
= asprintf(&s
, "%s %u %u %u %s",
947 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
951 r
= asprintf(&s
, "%s %u %u %s",
960 case DNS_TYPE_DNSKEY
: {
961 _cleanup_free_
char *alg
= NULL
;
964 r
= dnssec_algorithm_to_string_alloc(rr
->dnskey
.algorithm
, &alg
);
968 r
= asprintf(&s
, "%s %u %u %s %n",
977 r
= base64_append(&s
, n
,
978 rr
->dnskey
.key
, rr
->dnskey
.key_size
,
986 case DNS_TYPE_RRSIG
: {
987 _cleanup_free_
char *alg
= NULL
;
988 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
992 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
994 r
= dnssec_algorithm_to_string_alloc(rr
->rrsig
.algorithm
, &alg
);
998 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
1002 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
1007 * http://tools.ietf.org/html/rfc3597#section-5 */
1009 r
= asprintf(&s
, "%s %s%.*u %s %u %u %s %s %u %s %n",
1012 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
1015 rr
->rrsig
.original_ttl
,
1024 r
= base64_append(&s
, n
,
1025 rr
->rrsig
.signature
, rr
->rrsig
.signature_size
,
1034 t
= format_types(rr
->nsec
.types
);
1038 r
= asprintf(&s
, "%s %s %s",
1040 rr
->nsec
.next_domain_name
,
1046 case DNS_TYPE_NSEC3
: {
1047 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
1049 if (rr
->nsec3
.salt_size
> 0) {
1050 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
1055 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
1059 t
= format_types(rr
->nsec3
.types
);
1063 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
1065 rr
->nsec3
.algorithm
,
1067 rr
->nsec3
.iterations
,
1068 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
1078 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
1082 /* Format as documented in RFC 3597, Section 5 */
1083 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.size
, t
);
1093 int dns_resource_record_to_wire_format(DnsResourceRecord
*rr
, bool canonical
) {
1095 DnsPacket packet
= {
1097 .protocol
= DNS_PROTOCOL_DNS
,
1099 .refuse_compression
= true,
1100 .canonical_form
= canonical
,
1108 /* Generates the RR in wire-format, optionally in the
1109 * canonical form as discussed in the DNSSEC RFC 4034, Section
1110 * 6.2. We allocate a throw-away DnsPacket object on the stack
1111 * here, because we need some book-keeping for memory
1112 * management, and can reuse the DnsPacket serializer, that
1113 * can generate the canonical form, too, but also knows label
1114 * compression and suchlike. */
1116 if (rr
->wire_format
&& rr
->wire_format_canonical
== canonical
)
1119 r
= dns_packet_append_rr(&packet
, rr
, &start
, &rds
);
1124 assert(packet
._data
);
1126 free(rr
->wire_format
);
1127 rr
->wire_format
= packet
._data
;
1128 rr
->wire_format_size
= packet
.size
;
1129 rr
->wire_format_rdata_offset
= rds
;
1130 rr
->wire_format_canonical
= canonical
;
1132 packet
._data
= NULL
;
1133 dns_packet_unref(&packet
);
1138 int dns_resource_record_signer(DnsResourceRecord
*rr
, const char **ret
) {
1145 /* Returns the RRset's signer, if it is known. */
1147 if (rr
->n_skip_labels_signer
== (unsigned) -1)
1150 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1151 r
= dns_name_skip(n
, rr
->n_skip_labels_signer
, &n
);
1161 int dns_resource_record_source(DnsResourceRecord
*rr
, const char **ret
) {
1168 /* Returns the RRset's synthesizing source, if it is known. */
1170 if (rr
->n_skip_labels_source
== (unsigned) -1)
1173 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1174 r
= dns_name_skip(n
, rr
->n_skip_labels_source
, &n
);
1184 int dns_resource_record_is_signer(DnsResourceRecord
*rr
, const char *zone
) {
1190 r
= dns_resource_record_signer(rr
, &signer
);
1194 return dns_name_equal(zone
, signer
);
1197 int dns_resource_record_is_synthetic(DnsResourceRecord
*rr
) {
1202 /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */
1204 if (rr
->n_skip_labels_source
== (unsigned) -1)
1207 if (rr
->n_skip_labels_source
== 0)
1210 if (rr
->n_skip_labels_source
> 1)
1213 r
= dns_name_startswith(DNS_RESOURCE_KEY_NAME(rr
->key
), "*");
1220 static void dns_resource_record_hash_func(const void *i
, struct siphash
*state
) {
1221 const DnsResourceRecord
*rr
= i
;
1225 dns_resource_key_hash_func(rr
->key
, state
);
1227 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
1230 siphash24_compress(&rr
->srv
.priority
, sizeof(rr
->srv
.priority
), state
);
1231 siphash24_compress(&rr
->srv
.weight
, sizeof(rr
->srv
.weight
), state
);
1232 siphash24_compress(&rr
->srv
.port
, sizeof(rr
->srv
.port
), state
);
1233 dns_name_hash_func(rr
->srv
.name
, state
);
1238 case DNS_TYPE_CNAME
:
1239 case DNS_TYPE_DNAME
:
1240 dns_name_hash_func(rr
->ptr
.name
, state
);
1243 case DNS_TYPE_HINFO
:
1244 string_hash_func(rr
->hinfo
.cpu
, state
);
1245 string_hash_func(rr
->hinfo
.os
, state
);
1249 case DNS_TYPE_SPF
: {
1252 LIST_FOREACH(items
, j
, rr
->txt
.items
) {
1253 siphash24_compress(j
->data
, j
->length
, state
);
1255 /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab"
1256 * followed by "". */
1257 siphash24_compress_byte(0, state
);
1263 siphash24_compress(&rr
->a
.in_addr
, sizeof(rr
->a
.in_addr
), state
);
1267 siphash24_compress(&rr
->aaaa
.in6_addr
, sizeof(rr
->aaaa
.in6_addr
), state
);
1271 dns_name_hash_func(rr
->soa
.mname
, state
);
1272 dns_name_hash_func(rr
->soa
.rname
, state
);
1273 siphash24_compress(&rr
->soa
.serial
, sizeof(rr
->soa
.serial
), state
);
1274 siphash24_compress(&rr
->soa
.refresh
, sizeof(rr
->soa
.refresh
), state
);
1275 siphash24_compress(&rr
->soa
.retry
, sizeof(rr
->soa
.retry
), state
);
1276 siphash24_compress(&rr
->soa
.expire
, sizeof(rr
->soa
.expire
), state
);
1277 siphash24_compress(&rr
->soa
.minimum
, sizeof(rr
->soa
.minimum
), state
);
1281 siphash24_compress(&rr
->mx
.priority
, sizeof(rr
->mx
.priority
), state
);
1282 dns_name_hash_func(rr
->mx
.exchange
, state
);
1286 siphash24_compress(&rr
->loc
.version
, sizeof(rr
->loc
.version
), state
);
1287 siphash24_compress(&rr
->loc
.size
, sizeof(rr
->loc
.size
), state
);
1288 siphash24_compress(&rr
->loc
.horiz_pre
, sizeof(rr
->loc
.horiz_pre
), state
);
1289 siphash24_compress(&rr
->loc
.vert_pre
, sizeof(rr
->loc
.vert_pre
), state
);
1290 siphash24_compress(&rr
->loc
.latitude
, sizeof(rr
->loc
.latitude
), state
);
1291 siphash24_compress(&rr
->loc
.longitude
, sizeof(rr
->loc
.longitude
), state
);
1292 siphash24_compress(&rr
->loc
.altitude
, sizeof(rr
->loc
.altitude
), state
);
1295 case DNS_TYPE_SSHFP
:
1296 siphash24_compress(&rr
->sshfp
.algorithm
, sizeof(rr
->sshfp
.algorithm
), state
);
1297 siphash24_compress(&rr
->sshfp
.fptype
, sizeof(rr
->sshfp
.fptype
), state
);
1298 siphash24_compress(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
, state
);
1301 case DNS_TYPE_DNSKEY
:
1302 siphash24_compress(&rr
->dnskey
.flags
, sizeof(rr
->dnskey
.flags
), state
);
1303 siphash24_compress(&rr
->dnskey
.protocol
, sizeof(rr
->dnskey
.protocol
), state
);
1304 siphash24_compress(&rr
->dnskey
.algorithm
, sizeof(rr
->dnskey
.algorithm
), state
);
1305 siphash24_compress(rr
->dnskey
.key
, rr
->dnskey
.key_size
, state
);
1308 case DNS_TYPE_RRSIG
:
1309 siphash24_compress(&rr
->rrsig
.type_covered
, sizeof(rr
->rrsig
.type_covered
), state
);
1310 siphash24_compress(&rr
->rrsig
.algorithm
, sizeof(rr
->rrsig
.algorithm
), state
);
1311 siphash24_compress(&rr
->rrsig
.labels
, sizeof(rr
->rrsig
.labels
), state
);
1312 siphash24_compress(&rr
->rrsig
.original_ttl
, sizeof(rr
->rrsig
.original_ttl
), state
);
1313 siphash24_compress(&rr
->rrsig
.expiration
, sizeof(rr
->rrsig
.expiration
), state
);
1314 siphash24_compress(&rr
->rrsig
.inception
, sizeof(rr
->rrsig
.inception
), state
);
1315 siphash24_compress(&rr
->rrsig
.key_tag
, sizeof(rr
->rrsig
.key_tag
), state
);
1316 dns_name_hash_func(rr
->rrsig
.signer
, state
);
1317 siphash24_compress(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
, state
);
1321 dns_name_hash_func(rr
->nsec
.next_domain_name
, state
);
1322 /* FIXME: we leave out the type bitmap here. Hash
1323 * would be better if we'd take it into account
1328 siphash24_compress(&rr
->ds
.key_tag
, sizeof(rr
->ds
.key_tag
), state
);
1329 siphash24_compress(&rr
->ds
.algorithm
, sizeof(rr
->ds
.algorithm
), state
);
1330 siphash24_compress(&rr
->ds
.digest_type
, sizeof(rr
->ds
.digest_type
), state
);
1331 siphash24_compress(rr
->ds
.digest
, rr
->ds
.digest_size
, state
);
1334 case DNS_TYPE_NSEC3
:
1335 siphash24_compress(&rr
->nsec3
.algorithm
, sizeof(rr
->nsec3
.algorithm
), state
);
1336 siphash24_compress(&rr
->nsec3
.flags
, sizeof(rr
->nsec3
.flags
), state
);
1337 siphash24_compress(&rr
->nsec3
.iterations
, sizeof(rr
->nsec3
.iterations
), state
);
1338 siphash24_compress(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
, state
);
1339 siphash24_compress(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, state
);
1340 /* FIXME: We leave the bitmaps out */
1344 siphash24_compress(rr
->generic
.data
, rr
->generic
.size
, state
);
1349 static int dns_resource_record_compare_func(const void *a
, const void *b
) {
1350 const DnsResourceRecord
*x
= a
, *y
= b
;
1353 ret
= dns_resource_key_compare_func(x
->key
, y
->key
);
1357 if (dns_resource_record_equal(x
, y
))
1360 /* This is a bit dirty, we don't implement proper odering, but
1361 * the hashtable doesn't need ordering anyway, hence we don't
1363 return x
< y
? -1 : 1;
1366 const struct hash_ops dns_resource_record_hash_ops
= {
1367 .hash
= dns_resource_record_hash_func
,
1368 .compare
= dns_resource_record_compare_func
,
1371 DnsTxtItem
*dns_txt_item_free_all(DnsTxtItem
*i
) {
1380 return dns_txt_item_free_all(n
);
1383 bool dns_txt_item_equal(DnsTxtItem
*a
, DnsTxtItem
*b
) {
1394 if (a
->length
!= b
->length
)
1397 if (memcmp(a
->data
, b
->data
, a
->length
) != 0)
1400 return dns_txt_item_equal(a
->items_next
, b
->items_next
);
1403 static const char* const dnssec_algorithm_table
[_DNSSEC_ALGORITHM_MAX_DEFINED
] = {
1404 /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
1405 [DNSSEC_ALGORITHM_RSAMD5
] = "RSAMD5",
1406 [DNSSEC_ALGORITHM_DH
] = "DH",
1407 [DNSSEC_ALGORITHM_DSA
] = "DSA",
1408 [DNSSEC_ALGORITHM_ECC
] = "ECC",
1409 [DNSSEC_ALGORITHM_RSASHA1
] = "RSASHA1",
1410 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1
] = "DSA-NSEC3-SHA1",
1411 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
] = "RSASHA1-NSEC3-SHA1",
1412 [DNSSEC_ALGORITHM_RSASHA256
] = "RSASHA256",
1413 [DNSSEC_ALGORITHM_RSASHA512
] = "RSASHA512",
1414 [DNSSEC_ALGORITHM_ECC_GOST
] = "ECC-GOST",
1415 [DNSSEC_ALGORITHM_ECDSAP256SHA256
] = "ECDSAP256SHA256",
1416 [DNSSEC_ALGORITHM_ECDSAP384SHA384
] = "ECDSAP384SHA384",
1417 [DNSSEC_ALGORITHM_INDIRECT
] = "INDIRECT",
1418 [DNSSEC_ALGORITHM_PRIVATEDNS
] = "PRIVATEDNS",
1419 [DNSSEC_ALGORITHM_PRIVATEOID
] = "PRIVATEOID",
1421 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm
, int, 255);
1423 static const char* const dnssec_digest_table
[_DNSSEC_DIGEST_MAX_DEFINED
] = {
1424 /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
1425 [DNSSEC_DIGEST_SHA1
] = "SHA-1",
1426 [DNSSEC_DIGEST_SHA256
] = "SHA-256",
1427 [DNSSEC_DIGEST_GOST_R_34_11_94
] = "GOST_R_34.11-94",
1428 [DNSSEC_DIGEST_SHA384
] = "SHA-384",
1430 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest
, int, 255);