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
);
494 case DNS_TYPE_OPENPGPKEY
:
496 free(rr
->generic
.data
);
499 free(rr
->wire_format
);
500 dns_resource_key_unref(rr
->key
);
509 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
510 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
511 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
512 _cleanup_free_
char *ptr
= NULL
;
519 r
= dns_name_reverse(family
, address
, &ptr
);
523 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
529 rr
= dns_resource_record_new(key
);
533 rr
->ptr
.name
= strdup(hostname
);
543 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
544 DnsResourceRecord
*rr
;
550 if (family
== AF_INET
) {
552 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
556 rr
->a
.in_addr
= address
->in
;
558 } else if (family
== AF_INET6
) {
560 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
564 rr
->aaaa
.in6_addr
= address
->in6
;
566 return -EAFNOSUPPORT
;
573 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
582 r
= dns_resource_key_equal(a
->key
, b
->key
);
586 if (a
->unparseable
!= b
->unparseable
)
589 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
592 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
596 return a
->srv
.priority
== b
->srv
.priority
&&
597 a
->srv
.weight
== b
->srv
.weight
&&
598 a
->srv
.port
== b
->srv
.port
;
604 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
607 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
608 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
610 case DNS_TYPE_SPF
: /* exactly the same as TXT */
612 return dns_txt_item_equal(a
->txt
.items
, b
->txt
.items
);
615 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
618 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
621 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
624 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
628 return a
->soa
.serial
== b
->soa
.serial
&&
629 a
->soa
.refresh
== b
->soa
.refresh
&&
630 a
->soa
.retry
== b
->soa
.retry
&&
631 a
->soa
.expire
== b
->soa
.expire
&&
632 a
->soa
.minimum
== b
->soa
.minimum
;
635 if (a
->mx
.priority
!= b
->mx
.priority
)
638 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
641 assert(a
->loc
.version
== b
->loc
.version
);
643 return a
->loc
.size
== b
->loc
.size
&&
644 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
645 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
646 a
->loc
.latitude
== b
->loc
.latitude
&&
647 a
->loc
.longitude
== b
->loc
.longitude
&&
648 a
->loc
.altitude
== b
->loc
.altitude
;
651 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
652 a
->ds
.algorithm
== b
->ds
.algorithm
&&
653 a
->ds
.digest_type
== b
->ds
.digest_type
&&
654 a
->ds
.digest_size
== b
->ds
.digest_size
&&
655 memcmp(a
->ds
.digest
, b
->ds
.digest
, a
->ds
.digest_size
) == 0;
658 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
659 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
660 a
->sshfp
.fingerprint_size
== b
->sshfp
.fingerprint_size
&&
661 memcmp(a
->sshfp
.fingerprint
, b
->sshfp
.fingerprint
, a
->sshfp
.fingerprint_size
) == 0;
663 case DNS_TYPE_DNSKEY
:
664 return a
->dnskey
.flags
== b
->dnskey
.flags
&&
665 a
->dnskey
.protocol
== b
->dnskey
.protocol
&&
666 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
667 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
668 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
671 /* do the fast comparisons first */
672 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
673 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
674 a
->rrsig
.labels
!= b
->rrsig
.labels
||
675 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
676 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
677 a
->rrsig
.inception
!= b
->rrsig
.inception
||
678 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
679 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
680 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
683 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
686 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
687 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
690 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
691 a
->nsec3
.flags
== b
->nsec3
.flags
&&
692 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
693 a
->nsec3
.salt_size
== b
->nsec3
.salt_size
&&
694 memcmp(a
->nsec3
.salt
, b
->nsec3
.salt
, a
->nsec3
.salt_size
) == 0 &&
695 memcmp(a
->nsec3
.next_hashed_name
, b
->nsec3
.next_hashed_name
, a
->nsec3
.next_hashed_name_size
) == 0 &&
696 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
699 return a
->tlsa
.cert_usage
== b
->tlsa
.cert_usage
&&
700 a
->tlsa
.selector
== b
->tlsa
.selector
&&
701 a
->tlsa
.matching_type
== b
->tlsa
.matching_type
&&
702 a
->tlsa
.data_size
== b
->tlsa
.data_size
&&
703 memcmp(a
->tlsa
.data
, b
->tlsa
.data
, a
->tlsa
.data_size
) == 0;
706 return a
->generic
.size
== b
->generic
.size
&&
707 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
711 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
712 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
714 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
715 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
717 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
718 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
719 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
720 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
721 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
722 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
724 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
727 (lat
% 60000) / 1000.,
731 (lon
% 60000) / 1000.,
742 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
746 assert(l
> strlen("YYYYMMDDHHmmSS"));
748 if (!gmtime_r(&sec
, &tm
))
751 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
757 static char *format_types(Bitmap
*types
) {
758 _cleanup_strv_free_
char **strv
= NULL
;
759 _cleanup_free_
char *str
= NULL
;
764 BITMAP_FOREACH(type
, types
, i
) {
765 if (dns_type_to_string(type
)) {
766 r
= strv_extend(&strv
, dns_type_to_string(type
));
772 r
= asprintf(&t
, "TYPE%u", type
);
776 r
= strv_consume(&strv
, t
);
782 str
= strv_join(strv
, " ");
786 return strjoin("( ", str
, " )", NULL
);
789 static char *format_txt(DnsTxtItem
*first
) {
794 LIST_FOREACH(items
, i
, first
)
795 c
+= i
->length
* 4 + 3;
797 p
= s
= new(char, c
);
801 LIST_FOREACH(items
, i
, first
) {
809 for (j
= 0; j
< i
->length
; j
++) {
810 if (i
->data
[j
] < ' ' || i
->data
[j
] == '"' || i
->data
[j
] >= 127) {
812 *(p
++) = '0' + (i
->data
[j
] / 100);
813 *(p
++) = '0' + ((i
->data
[j
] / 10) % 10);
814 *(p
++) = '0' + (i
->data
[j
] % 10);
826 const char *dns_resource_record_to_string(DnsResourceRecord
*rr
) {
827 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
834 return rr
->to_string
;
836 r
= dns_resource_key_to_string(rr
->key
, &k
);
840 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
843 r
= asprintf(&s
, "%s %u %u %u %s",
848 strna(rr
->srv
.name
));
857 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
864 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
869 case DNS_TYPE_SPF
: /* exactly the same as TXT */
871 t
= format_txt(rr
->txt
.items
);
875 s
= strjoin(k
, " ", t
, NULL
);
881 _cleanup_free_
char *x
= NULL
;
883 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
887 s
= strjoin(k
, " ", x
, NULL
);
894 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
898 s
= strjoin(k
, " ", t
, NULL
);
904 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
906 strna(rr
->soa
.mname
),
907 strna(rr
->soa
.rname
),
918 r
= asprintf(&s
, "%s %u %s",
927 assert(rr
->loc
.version
== 0);
929 t
= format_location(rr
->loc
.latitude
,
938 s
= strjoin(k
, " ", t
, NULL
);
944 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
948 r
= asprintf(&s
, "%s %u %u %u %s",
959 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
963 r
= asprintf(&s
, "%s %u %u %s",
972 case DNS_TYPE_DNSKEY
: {
973 _cleanup_free_
char *alg
= NULL
;
976 r
= dnssec_algorithm_to_string_alloc(rr
->dnskey
.algorithm
, &alg
);
980 r
= asprintf(&s
, "%s %u %u %s %n",
989 r
= base64_append(&s
, n
,
990 rr
->dnskey
.key
, rr
->dnskey
.key_size
,
998 case DNS_TYPE_RRSIG
: {
999 _cleanup_free_
char *alg
= NULL
;
1000 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
1004 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
1006 r
= dnssec_algorithm_to_string_alloc(rr
->rrsig
.algorithm
, &alg
);
1010 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
1014 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
1019 * http://tools.ietf.org/html/rfc3597#section-5 */
1021 r
= asprintf(&s
, "%s %s%.*u %s %u %u %s %s %u %s %n",
1024 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
1027 rr
->rrsig
.original_ttl
,
1036 r
= base64_append(&s
, n
,
1037 rr
->rrsig
.signature
, rr
->rrsig
.signature_size
,
1046 t
= format_types(rr
->nsec
.types
);
1050 r
= asprintf(&s
, "%s %s %s",
1052 rr
->nsec
.next_domain_name
,
1058 case DNS_TYPE_NSEC3
: {
1059 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
1061 if (rr
->nsec3
.salt_size
> 0) {
1062 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
1067 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
1071 t
= format_types(rr
->nsec3
.types
);
1075 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
1077 rr
->nsec3
.algorithm
,
1079 rr
->nsec3
.iterations
,
1080 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
1089 case DNS_TYPE_TLSA
: {
1090 const char *cert_usage
, *selector
, *matching_type
;
1094 cert_usage
= tlsa_cert_usage_to_string(rr
->tlsa
.cert_usage
);
1095 selector
= tlsa_selector_to_string(rr
->tlsa
.selector
);
1096 matching_type
= tlsa_matching_type_to_string(rr
->tlsa
.matching_type
);
1098 r
= asprintf(&s
, "%s %u %u %u %n",
1100 rr
->tlsa
.cert_usage
,
1102 rr
->tlsa
.matching_type
,
1107 r
= base64_append(&s
, n
,
1108 rr
->tlsa
.data
, rr
->tlsa
.data_size
,
1113 r
= asprintf(&ss
, "%s\n"
1114 "%*s-- Cert. usage: %s\n"
1115 "%*s-- Selector: %s\n"
1116 "%*s-- Matching type: %s",
1118 n
- 6, "", cert_usage
,
1119 n
- 6, "", selector
,
1120 n
- 6, "", matching_type
);
1129 case DNS_TYPE_OPENPGPKEY
: {
1132 r
= asprintf(&s
, "%s %n",
1138 r
= base64_append(&s
, n
,
1139 rr
->generic
.data
, rr
->generic
.size
,
1147 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
1151 /* Format as documented in RFC 3597, Section 5 */
1152 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.size
, t
);
1162 int dns_resource_record_to_wire_format(DnsResourceRecord
*rr
, bool canonical
) {
1164 DnsPacket packet
= {
1166 .protocol
= DNS_PROTOCOL_DNS
,
1168 .refuse_compression
= true,
1169 .canonical_form
= canonical
,
1177 /* Generates the RR in wire-format, optionally in the
1178 * canonical form as discussed in the DNSSEC RFC 4034, Section
1179 * 6.2. We allocate a throw-away DnsPacket object on the stack
1180 * here, because we need some book-keeping for memory
1181 * management, and can reuse the DnsPacket serializer, that
1182 * can generate the canonical form, too, but also knows label
1183 * compression and suchlike. */
1185 if (rr
->wire_format
&& rr
->wire_format_canonical
== canonical
)
1188 r
= dns_packet_append_rr(&packet
, rr
, &start
, &rds
);
1193 assert(packet
._data
);
1195 free(rr
->wire_format
);
1196 rr
->wire_format
= packet
._data
;
1197 rr
->wire_format_size
= packet
.size
;
1198 rr
->wire_format_rdata_offset
= rds
;
1199 rr
->wire_format_canonical
= canonical
;
1201 packet
._data
= NULL
;
1202 dns_packet_unref(&packet
);
1207 int dns_resource_record_signer(DnsResourceRecord
*rr
, const char **ret
) {
1214 /* Returns the RRset's signer, if it is known. */
1216 if (rr
->n_skip_labels_signer
== (unsigned) -1)
1219 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1220 r
= dns_name_skip(n
, rr
->n_skip_labels_signer
, &n
);
1230 int dns_resource_record_source(DnsResourceRecord
*rr
, const char **ret
) {
1237 /* Returns the RRset's synthesizing source, if it is known. */
1239 if (rr
->n_skip_labels_source
== (unsigned) -1)
1242 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1243 r
= dns_name_skip(n
, rr
->n_skip_labels_source
, &n
);
1253 int dns_resource_record_is_signer(DnsResourceRecord
*rr
, const char *zone
) {
1259 r
= dns_resource_record_signer(rr
, &signer
);
1263 return dns_name_equal(zone
, signer
);
1266 int dns_resource_record_is_synthetic(DnsResourceRecord
*rr
) {
1271 /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */
1273 if (rr
->n_skip_labels_source
== (unsigned) -1)
1276 if (rr
->n_skip_labels_source
== 0)
1279 if (rr
->n_skip_labels_source
> 1)
1282 r
= dns_name_startswith(DNS_RESOURCE_KEY_NAME(rr
->key
), "*");
1289 static void dns_resource_record_hash_func(const void *i
, struct siphash
*state
) {
1290 const DnsResourceRecord
*rr
= i
;
1294 dns_resource_key_hash_func(rr
->key
, state
);
1296 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
1299 siphash24_compress(&rr
->srv
.priority
, sizeof(rr
->srv
.priority
), state
);
1300 siphash24_compress(&rr
->srv
.weight
, sizeof(rr
->srv
.weight
), state
);
1301 siphash24_compress(&rr
->srv
.port
, sizeof(rr
->srv
.port
), state
);
1302 dns_name_hash_func(rr
->srv
.name
, state
);
1307 case DNS_TYPE_CNAME
:
1308 case DNS_TYPE_DNAME
:
1309 dns_name_hash_func(rr
->ptr
.name
, state
);
1312 case DNS_TYPE_HINFO
:
1313 string_hash_func(rr
->hinfo
.cpu
, state
);
1314 string_hash_func(rr
->hinfo
.os
, state
);
1318 case DNS_TYPE_SPF
: {
1321 LIST_FOREACH(items
, j
, rr
->txt
.items
) {
1322 siphash24_compress(j
->data
, j
->length
, state
);
1324 /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab"
1325 * followed by "". */
1326 siphash24_compress_byte(0, state
);
1332 siphash24_compress(&rr
->a
.in_addr
, sizeof(rr
->a
.in_addr
), state
);
1336 siphash24_compress(&rr
->aaaa
.in6_addr
, sizeof(rr
->aaaa
.in6_addr
), state
);
1340 dns_name_hash_func(rr
->soa
.mname
, state
);
1341 dns_name_hash_func(rr
->soa
.rname
, state
);
1342 siphash24_compress(&rr
->soa
.serial
, sizeof(rr
->soa
.serial
), state
);
1343 siphash24_compress(&rr
->soa
.refresh
, sizeof(rr
->soa
.refresh
), state
);
1344 siphash24_compress(&rr
->soa
.retry
, sizeof(rr
->soa
.retry
), state
);
1345 siphash24_compress(&rr
->soa
.expire
, sizeof(rr
->soa
.expire
), state
);
1346 siphash24_compress(&rr
->soa
.minimum
, sizeof(rr
->soa
.minimum
), state
);
1350 siphash24_compress(&rr
->mx
.priority
, sizeof(rr
->mx
.priority
), state
);
1351 dns_name_hash_func(rr
->mx
.exchange
, state
);
1355 siphash24_compress(&rr
->loc
.version
, sizeof(rr
->loc
.version
), state
);
1356 siphash24_compress(&rr
->loc
.size
, sizeof(rr
->loc
.size
), state
);
1357 siphash24_compress(&rr
->loc
.horiz_pre
, sizeof(rr
->loc
.horiz_pre
), state
);
1358 siphash24_compress(&rr
->loc
.vert_pre
, sizeof(rr
->loc
.vert_pre
), state
);
1359 siphash24_compress(&rr
->loc
.latitude
, sizeof(rr
->loc
.latitude
), state
);
1360 siphash24_compress(&rr
->loc
.longitude
, sizeof(rr
->loc
.longitude
), state
);
1361 siphash24_compress(&rr
->loc
.altitude
, sizeof(rr
->loc
.altitude
), state
);
1364 case DNS_TYPE_SSHFP
:
1365 siphash24_compress(&rr
->sshfp
.algorithm
, sizeof(rr
->sshfp
.algorithm
), state
);
1366 siphash24_compress(&rr
->sshfp
.fptype
, sizeof(rr
->sshfp
.fptype
), state
);
1367 siphash24_compress(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
, state
);
1370 case DNS_TYPE_DNSKEY
:
1371 siphash24_compress(&rr
->dnskey
.flags
, sizeof(rr
->dnskey
.flags
), state
);
1372 siphash24_compress(&rr
->dnskey
.protocol
, sizeof(rr
->dnskey
.protocol
), state
);
1373 siphash24_compress(&rr
->dnskey
.algorithm
, sizeof(rr
->dnskey
.algorithm
), state
);
1374 siphash24_compress(rr
->dnskey
.key
, rr
->dnskey
.key_size
, state
);
1377 case DNS_TYPE_RRSIG
:
1378 siphash24_compress(&rr
->rrsig
.type_covered
, sizeof(rr
->rrsig
.type_covered
), state
);
1379 siphash24_compress(&rr
->rrsig
.algorithm
, sizeof(rr
->rrsig
.algorithm
), state
);
1380 siphash24_compress(&rr
->rrsig
.labels
, sizeof(rr
->rrsig
.labels
), state
);
1381 siphash24_compress(&rr
->rrsig
.original_ttl
, sizeof(rr
->rrsig
.original_ttl
), state
);
1382 siphash24_compress(&rr
->rrsig
.expiration
, sizeof(rr
->rrsig
.expiration
), state
);
1383 siphash24_compress(&rr
->rrsig
.inception
, sizeof(rr
->rrsig
.inception
), state
);
1384 siphash24_compress(&rr
->rrsig
.key_tag
, sizeof(rr
->rrsig
.key_tag
), state
);
1385 dns_name_hash_func(rr
->rrsig
.signer
, state
);
1386 siphash24_compress(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
, state
);
1390 dns_name_hash_func(rr
->nsec
.next_domain_name
, state
);
1391 /* FIXME: we leave out the type bitmap here. Hash
1392 * would be better if we'd take it into account
1397 siphash24_compress(&rr
->ds
.key_tag
, sizeof(rr
->ds
.key_tag
), state
);
1398 siphash24_compress(&rr
->ds
.algorithm
, sizeof(rr
->ds
.algorithm
), state
);
1399 siphash24_compress(&rr
->ds
.digest_type
, sizeof(rr
->ds
.digest_type
), state
);
1400 siphash24_compress(rr
->ds
.digest
, rr
->ds
.digest_size
, state
);
1403 case DNS_TYPE_NSEC3
:
1404 siphash24_compress(&rr
->nsec3
.algorithm
, sizeof(rr
->nsec3
.algorithm
), state
);
1405 siphash24_compress(&rr
->nsec3
.flags
, sizeof(rr
->nsec3
.flags
), state
);
1406 siphash24_compress(&rr
->nsec3
.iterations
, sizeof(rr
->nsec3
.iterations
), state
);
1407 siphash24_compress(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
, state
);
1408 siphash24_compress(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, state
);
1409 /* FIXME: We leave the bitmaps out */
1413 siphash24_compress(&rr
->tlsa
.cert_usage
, sizeof(rr
->tlsa
.cert_usage
), state
);
1414 siphash24_compress(&rr
->tlsa
.selector
, sizeof(rr
->tlsa
.selector
), state
);
1415 siphash24_compress(&rr
->tlsa
.matching_type
, sizeof(rr
->tlsa
.matching_type
), state
);
1416 siphash24_compress(&rr
->tlsa
.data
, rr
->tlsa
.data_size
, state
);
1419 case DNS_TYPE_OPENPGPKEY
:
1421 siphash24_compress(rr
->generic
.data
, rr
->generic
.size
, state
);
1426 static int dns_resource_record_compare_func(const void *a
, const void *b
) {
1427 const DnsResourceRecord
*x
= a
, *y
= b
;
1430 ret
= dns_resource_key_compare_func(x
->key
, y
->key
);
1434 if (dns_resource_record_equal(x
, y
))
1437 /* This is a bit dirty, we don't implement proper odering, but
1438 * the hashtable doesn't need ordering anyway, hence we don't
1440 return x
< y
? -1 : 1;
1443 const struct hash_ops dns_resource_record_hash_ops
= {
1444 .hash
= dns_resource_record_hash_func
,
1445 .compare
= dns_resource_record_compare_func
,
1448 DnsTxtItem
*dns_txt_item_free_all(DnsTxtItem
*i
) {
1457 return dns_txt_item_free_all(n
);
1460 bool dns_txt_item_equal(DnsTxtItem
*a
, DnsTxtItem
*b
) {
1471 if (a
->length
!= b
->length
)
1474 if (memcmp(a
->data
, b
->data
, a
->length
) != 0)
1477 return dns_txt_item_equal(a
->items_next
, b
->items_next
);
1480 static const char* const dnssec_algorithm_table
[_DNSSEC_ALGORITHM_MAX_DEFINED
] = {
1481 /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
1482 [DNSSEC_ALGORITHM_RSAMD5
] = "RSAMD5",
1483 [DNSSEC_ALGORITHM_DH
] = "DH",
1484 [DNSSEC_ALGORITHM_DSA
] = "DSA",
1485 [DNSSEC_ALGORITHM_ECC
] = "ECC",
1486 [DNSSEC_ALGORITHM_RSASHA1
] = "RSASHA1",
1487 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1
] = "DSA-NSEC3-SHA1",
1488 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
] = "RSASHA1-NSEC3-SHA1",
1489 [DNSSEC_ALGORITHM_RSASHA256
] = "RSASHA256",
1490 [DNSSEC_ALGORITHM_RSASHA512
] = "RSASHA512",
1491 [DNSSEC_ALGORITHM_ECC_GOST
] = "ECC-GOST",
1492 [DNSSEC_ALGORITHM_ECDSAP256SHA256
] = "ECDSAP256SHA256",
1493 [DNSSEC_ALGORITHM_ECDSAP384SHA384
] = "ECDSAP384SHA384",
1494 [DNSSEC_ALGORITHM_INDIRECT
] = "INDIRECT",
1495 [DNSSEC_ALGORITHM_PRIVATEDNS
] = "PRIVATEDNS",
1496 [DNSSEC_ALGORITHM_PRIVATEOID
] = "PRIVATEOID",
1498 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm
, int, 255);
1500 static const char* const dnssec_digest_table
[_DNSSEC_DIGEST_MAX_DEFINED
] = {
1501 /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
1502 [DNSSEC_DIGEST_SHA1
] = "SHA-1",
1503 [DNSSEC_DIGEST_SHA256
] = "SHA-256",
1504 [DNSSEC_DIGEST_GOST_R_34_11_94
] = "GOST_R_34.11-94",
1505 [DNSSEC_DIGEST_SHA384
] = "SHA-384",
1507 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest
, int, 255);