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-dnssec.h"
29 #include "resolved-dns-packet.h"
30 #include "resolved-dns-rr.h"
31 #include "string-table.h"
32 #include "string-util.h"
34 #include "terminal-util.h"
36 DnsResourceKey
* dns_resource_key_new(uint16_t class, uint16_t type
, const char *name
) {
43 k
= malloc0(sizeof(DnsResourceKey
) + l
+ 1);
51 strcpy((char*) k
+ sizeof(DnsResourceKey
), name
);
56 DnsResourceKey
* dns_resource_key_new_redirect(const DnsResourceKey
*key
, const DnsResourceRecord
*cname
) {
62 assert(IN_SET(cname
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
));
64 if (cname
->key
->type
== DNS_TYPE_CNAME
)
65 return dns_resource_key_new(key
->class, key
->type
, cname
->cname
.name
);
68 char *destination
= NULL
;
70 r
= dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(cname
->key
), cname
->dname
.name
, &destination
);
74 return dns_resource_key_ref((DnsResourceKey
*) key
);
76 k
= dns_resource_key_new_consume(key
->class, key
->type
, destination
);
86 int dns_resource_key_new_append_suffix(DnsResourceKey
**ret
, DnsResourceKey
*key
, char *name
) {
87 DnsResourceKey
*new_key
;
95 if (dns_name_is_root(name
)) {
96 *ret
= dns_resource_key_ref(key
);
100 r
= dns_name_concat(DNS_RESOURCE_KEY_NAME(key
), name
, &joined
);
104 new_key
= dns_resource_key_new_consume(key
->class, key
->type
, joined
);
114 DnsResourceKey
* dns_resource_key_new_consume(uint16_t class, uint16_t type
, char *name
) {
119 k
= new0(DnsResourceKey
, 1);
131 DnsResourceKey
* dns_resource_key_ref(DnsResourceKey
*k
) {
136 /* Static/const keys created with DNS_RESOURCE_KEY_CONST will
137 * set this to -1, they should not be reffed/unreffed */
138 assert(k
->n_ref
!= (unsigned) -1);
140 assert(k
->n_ref
> 0);
146 DnsResourceKey
* dns_resource_key_unref(DnsResourceKey
*k
) {
150 assert(k
->n_ref
!= (unsigned) -1);
151 assert(k
->n_ref
> 0);
162 bool dns_resource_key_is_address(const DnsResourceKey
*key
) {
165 /* Check if this is an A or AAAA resource key */
167 return key
->class == DNS_CLASS_IN
&& IN_SET(key
->type
, DNS_TYPE_A
, DNS_TYPE_AAAA
);
170 int dns_resource_key_equal(const DnsResourceKey
*a
, const DnsResourceKey
*b
) {
176 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(a
), DNS_RESOURCE_KEY_NAME(b
));
180 if (a
->class != b
->class)
183 if (a
->type
!= b
->type
)
189 int dns_resource_key_match_rr(const DnsResourceKey
*key
, DnsResourceRecord
*rr
, const char *search_domain
) {
198 /* Checks if an rr matches the specified key. If a search
199 * domain is specified, it will also be checked if the key
200 * with the search domain suffixed might match the RR. */
202 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
205 if (rr
->key
->type
!= key
->type
&& key
->type
!= DNS_TYPE_ANY
)
208 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
213 _cleanup_free_
char *joined
= NULL
;
215 r
= dns_name_concat(DNS_RESOURCE_KEY_NAME(key
), search_domain
, &joined
);
219 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), joined
);
225 int dns_resource_key_match_cname_or_dname(const DnsResourceKey
*key
, const DnsResourceKey
*cname
, const char *search_domain
) {
231 if (cname
->class != key
->class && key
->class != DNS_CLASS_ANY
)
234 if (cname
->type
== DNS_TYPE_CNAME
)
235 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(cname
));
236 else if (cname
->type
== DNS_TYPE_DNAME
)
237 r
= dns_name_endswith(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(cname
));
245 _cleanup_free_
char *joined
= NULL
;
247 r
= dns_name_concat(DNS_RESOURCE_KEY_NAME(key
), search_domain
, &joined
);
251 if (cname
->type
== DNS_TYPE_CNAME
)
252 return dns_name_equal(joined
, DNS_RESOURCE_KEY_NAME(cname
));
253 else if (cname
->type
== DNS_TYPE_DNAME
)
254 return dns_name_endswith(joined
, DNS_RESOURCE_KEY_NAME(cname
));
260 int dns_resource_key_match_soa(const DnsResourceKey
*key
, const DnsResourceKey
*soa
) {
264 /* Checks whether 'soa' is a SOA record for the specified key. */
266 if (soa
->class != key
->class)
269 if (soa
->type
!= DNS_TYPE_SOA
)
272 return dns_name_endswith(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(soa
));
275 static void dns_resource_key_hash_func(const void *i
, struct siphash
*state
) {
276 const DnsResourceKey
*k
= i
;
280 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k
), state
);
281 siphash24_compress(&k
->class, sizeof(k
->class), state
);
282 siphash24_compress(&k
->type
, sizeof(k
->type
), state
);
285 static int dns_resource_key_compare_func(const void *a
, const void *b
) {
286 const DnsResourceKey
*x
= a
, *y
= b
;
289 ret
= dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x
), DNS_RESOURCE_KEY_NAME(y
));
293 if (x
->type
< y
->type
)
295 if (x
->type
> y
->type
)
298 if (x
->class < y
->class)
300 if (x
->class > y
->class)
306 const struct hash_ops dns_resource_key_hash_ops
= {
307 .hash
= dns_resource_key_hash_func
,
308 .compare
= dns_resource_key_compare_func
311 int dns_resource_key_to_string(const DnsResourceKey
*key
, char **ret
) {
312 char cbuf
[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf
[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
313 const char *c
, *t
, *n
;
316 /* If we cannot convert the CLASS/TYPE into a known string,
317 use the format recommended by RFC 3597, Section 5. */
319 c
= dns_class_to_string(key
->class);
321 sprintf(cbuf
, "CLASS%u", key
->class);
325 t
= dns_type_to_string(key
->type
);
327 sprintf(tbuf
, "TYPE%u", key
->type
);
331 n
= DNS_RESOURCE_KEY_NAME(key
);
332 if (asprintf(&s
, "%s%s %s %-5s", n
, endswith(n
, ".") ? "" : ".", c
, t
) < 0)
339 bool dns_resource_key_reduce(DnsResourceKey
**a
, DnsResourceKey
**b
) {
343 /* Try to replace one RR key by another if they are identical, thus saving a bit of memory. Note that we do
344 * this only for RR keys, not for RRs themselves, as they carry a lot of additional metadata (where they come
345 * from, validity data, and suchlike), and cannot be replaced so easily by other RRs that have the same
346 * superficial data. */
353 /* We refuse merging const keys */
354 if ((*a
)->n_ref
== (unsigned) -1)
356 if ((*b
)->n_ref
== (unsigned) -1)
359 /* Already the same? */
363 /* Are they really identical? */
364 if (dns_resource_key_equal(*a
, *b
) <= 0)
367 /* Keep the one which already has more references. */
368 if ((*a
)->n_ref
> (*b
)->n_ref
) {
369 dns_resource_key_unref(*b
);
370 *b
= dns_resource_key_ref(*a
);
372 dns_resource_key_unref(*a
);
373 *a
= dns_resource_key_ref(*b
);
379 DnsResourceRecord
* dns_resource_record_new(DnsResourceKey
*key
) {
380 DnsResourceRecord
*rr
;
382 rr
= new0(DnsResourceRecord
, 1);
387 rr
->key
= dns_resource_key_ref(key
);
388 rr
->expiry
= USEC_INFINITY
;
389 rr
->n_skip_labels_signer
= rr
->n_skip_labels_source
= (unsigned) -1;
394 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
395 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
397 key
= dns_resource_key_new(class, type
, name
);
401 return dns_resource_record_new(key
);
404 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
408 assert(rr
->n_ref
> 0);
414 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
418 assert(rr
->n_ref
> 0);
426 switch(rr
->key
->type
) {
446 dns_txt_item_free_all(rr
->txt
.items
);
455 free(rr
->mx
.exchange
);
463 free(rr
->sshfp
.fingerprint
);
466 case DNS_TYPE_DNSKEY
:
467 free(rr
->dnskey
.key
);
471 free(rr
->rrsig
.signer
);
472 free(rr
->rrsig
.signature
);
476 free(rr
->nsec
.next_domain_name
);
477 bitmap_free(rr
->nsec
.types
);
481 free(rr
->nsec3
.next_hashed_name
);
482 free(rr
->nsec3
.salt
);
483 bitmap_free(rr
->nsec3
.types
);
495 case DNS_TYPE_OPENPGPKEY
:
497 free(rr
->generic
.data
);
500 free(rr
->wire_format
);
501 dns_resource_key_unref(rr
->key
);
510 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
511 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
512 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
513 _cleanup_free_
char *ptr
= NULL
;
520 r
= dns_name_reverse(family
, address
, &ptr
);
524 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
530 rr
= dns_resource_record_new(key
);
534 rr
->ptr
.name
= strdup(hostname
);
544 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
545 DnsResourceRecord
*rr
;
551 if (family
== AF_INET
) {
553 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
557 rr
->a
.in_addr
= address
->in
;
559 } else if (family
== AF_INET6
) {
561 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
565 rr
->aaaa
.in6_addr
= address
->in6
;
567 return -EAFNOSUPPORT
;
574 #define FIELD_EQUAL(a, b, field) \
575 ((a).field ## _size == (b).field ## _size && \
576 memcmp((a).field, (b).field, (a).field ## _size) == 0)
578 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
587 r
= dns_resource_key_equal(a
->key
, b
->key
);
591 if (a
->unparseable
!= b
->unparseable
)
594 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
597 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
601 return a
->srv
.priority
== b
->srv
.priority
&&
602 a
->srv
.weight
== b
->srv
.weight
&&
603 a
->srv
.port
== b
->srv
.port
;
609 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
612 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
613 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
615 case DNS_TYPE_SPF
: /* exactly the same as TXT */
617 return dns_txt_item_equal(a
->txt
.items
, b
->txt
.items
);
620 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
623 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
626 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
629 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
633 return a
->soa
.serial
== b
->soa
.serial
&&
634 a
->soa
.refresh
== b
->soa
.refresh
&&
635 a
->soa
.retry
== b
->soa
.retry
&&
636 a
->soa
.expire
== b
->soa
.expire
&&
637 a
->soa
.minimum
== b
->soa
.minimum
;
640 if (a
->mx
.priority
!= b
->mx
.priority
)
643 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
646 assert(a
->loc
.version
== b
->loc
.version
);
648 return a
->loc
.size
== b
->loc
.size
&&
649 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
650 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
651 a
->loc
.latitude
== b
->loc
.latitude
&&
652 a
->loc
.longitude
== b
->loc
.longitude
&&
653 a
->loc
.altitude
== b
->loc
.altitude
;
656 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
657 a
->ds
.algorithm
== b
->ds
.algorithm
&&
658 a
->ds
.digest_type
== b
->ds
.digest_type
&&
659 FIELD_EQUAL(a
->ds
, b
->ds
, digest
);
662 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
663 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
664 FIELD_EQUAL(a
->sshfp
, b
->sshfp
, fingerprint
);
666 case DNS_TYPE_DNSKEY
:
667 return a
->dnskey
.flags
== b
->dnskey
.flags
&&
668 a
->dnskey
.protocol
== b
->dnskey
.protocol
&&
669 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
670 FIELD_EQUAL(a
->dnskey
, b
->dnskey
, key
);
673 /* do the fast comparisons first */
674 return a
->rrsig
.type_covered
== b
->rrsig
.type_covered
&&
675 a
->rrsig
.algorithm
== b
->rrsig
.algorithm
&&
676 a
->rrsig
.labels
== b
->rrsig
.labels
&&
677 a
->rrsig
.original_ttl
== b
->rrsig
.original_ttl
&&
678 a
->rrsig
.expiration
== b
->rrsig
.expiration
&&
679 a
->rrsig
.inception
== b
->rrsig
.inception
&&
680 a
->rrsig
.key_tag
== b
->rrsig
.key_tag
&&
681 FIELD_EQUAL(a
->rrsig
, b
->rrsig
, signature
) &&
682 dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
685 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
686 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
689 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
690 a
->nsec3
.flags
== b
->nsec3
.flags
&&
691 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
692 FIELD_EQUAL(a
->nsec3
, b
->nsec3
, salt
) &&
693 FIELD_EQUAL(a
->nsec3
, b
->nsec3
, next_hashed_name
) &&
694 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
697 return a
->tlsa
.cert_usage
== b
->tlsa
.cert_usage
&&
698 a
->tlsa
.selector
== b
->tlsa
.selector
&&
699 a
->tlsa
.matching_type
== b
->tlsa
.matching_type
&&
700 FIELD_EQUAL(a
->tlsa
, b
->tlsa
, data
);
703 return FIELD_EQUAL(a
->generic
, b
->generic
, data
);
707 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
708 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
710 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
711 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
713 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
714 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
715 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
716 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
717 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
718 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
720 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
723 (lat
% 60000) / 1000.,
727 (lon
% 60000) / 1000.,
738 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
742 assert(l
> strlen("YYYYMMDDHHmmSS"));
744 if (!gmtime_r(&sec
, &tm
))
747 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
753 static char *format_types(Bitmap
*types
) {
754 _cleanup_strv_free_
char **strv
= NULL
;
755 _cleanup_free_
char *str
= NULL
;
760 BITMAP_FOREACH(type
, types
, i
) {
761 if (dns_type_to_string(type
)) {
762 r
= strv_extend(&strv
, dns_type_to_string(type
));
768 r
= asprintf(&t
, "TYPE%u", type
);
772 r
= strv_consume(&strv
, t
);
778 str
= strv_join(strv
, " ");
782 return strjoin("( ", str
, " )", NULL
);
785 static char *format_txt(DnsTxtItem
*first
) {
790 LIST_FOREACH(items
, i
, first
)
791 c
+= i
->length
* 4 + 3;
793 p
= s
= new(char, c
);
797 LIST_FOREACH(items
, i
, first
) {
805 for (j
= 0; j
< i
->length
; j
++) {
806 if (i
->data
[j
] < ' ' || i
->data
[j
] == '"' || i
->data
[j
] >= 127) {
808 *(p
++) = '0' + (i
->data
[j
] / 100);
809 *(p
++) = '0' + ((i
->data
[j
] / 10) % 10);
810 *(p
++) = '0' + (i
->data
[j
] % 10);
822 const char *dns_resource_record_to_string(DnsResourceRecord
*rr
) {
823 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
830 return rr
->to_string
;
832 r
= dns_resource_key_to_string(rr
->key
, &k
);
836 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
839 r
= asprintf(&s
, "%s %u %u %u %s",
844 strna(rr
->srv
.name
));
853 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
860 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
865 case DNS_TYPE_SPF
: /* exactly the same as TXT */
867 t
= format_txt(rr
->txt
.items
);
871 s
= strjoin(k
, " ", t
, NULL
);
877 _cleanup_free_
char *x
= NULL
;
879 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
883 s
= strjoin(k
, " ", x
, NULL
);
890 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
894 s
= strjoin(k
, " ", t
, NULL
);
900 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
902 strna(rr
->soa
.mname
),
903 strna(rr
->soa
.rname
),
914 r
= asprintf(&s
, "%s %u %s",
923 assert(rr
->loc
.version
== 0);
925 t
= format_location(rr
->loc
.latitude
,
934 s
= strjoin(k
, " ", t
, NULL
);
940 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
944 r
= asprintf(&s
, "%s %u %u %u %s",
955 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
959 r
= asprintf(&s
, "%s %u %u %s",
968 case DNS_TYPE_DNSKEY
: {
969 _cleanup_free_
char *alg
= NULL
;
974 key_tag
= dnssec_keytag(rr
, true);
976 r
= dnssec_algorithm_to_string_alloc(rr
->dnskey
.algorithm
, &alg
);
980 r
= asprintf(&s
, "%s %n%u %u %s %n",
990 r
= base64_append(&s
, n
,
991 rr
->dnskey
.key
, rr
->dnskey
.key_size
,
996 r
= asprintf(&ss
, "%s\n"
997 "%*s-- Flags:%s%s%s\n"
1001 rr
->dnskey
.flags
& DNSKEY_FLAG_SEP
? " SEP" : "",
1002 rr
->dnskey
.flags
& DNSKEY_FLAG_REVOKE
? " REVOKE" : "",
1003 rr
->dnskey
.flags
& DNSKEY_FLAG_ZONE_KEY
? " ZONE_KEY" : "",
1014 case DNS_TYPE_RRSIG
: {
1015 _cleanup_free_
char *alg
= NULL
;
1016 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
1020 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
1022 r
= dnssec_algorithm_to_string_alloc(rr
->rrsig
.algorithm
, &alg
);
1026 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
1030 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
1035 * http://tools.ietf.org/html/rfc3597#section-5 */
1037 r
= asprintf(&s
, "%s %s%.*u %s %u %u %s %s %u %s %n",
1040 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
1043 rr
->rrsig
.original_ttl
,
1052 r
= base64_append(&s
, n
,
1053 rr
->rrsig
.signature
, rr
->rrsig
.signature_size
,
1062 t
= format_types(rr
->nsec
.types
);
1066 r
= asprintf(&s
, "%s %s %s",
1068 rr
->nsec
.next_domain_name
,
1074 case DNS_TYPE_NSEC3
: {
1075 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
1077 if (rr
->nsec3
.salt_size
> 0) {
1078 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
1083 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
1087 t
= format_types(rr
->nsec3
.types
);
1091 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
1093 rr
->nsec3
.algorithm
,
1095 rr
->nsec3
.iterations
,
1096 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
1105 case DNS_TYPE_TLSA
: {
1106 const char *cert_usage
, *selector
, *matching_type
;
1110 cert_usage
= tlsa_cert_usage_to_string(rr
->tlsa
.cert_usage
);
1111 selector
= tlsa_selector_to_string(rr
->tlsa
.selector
);
1112 matching_type
= tlsa_matching_type_to_string(rr
->tlsa
.matching_type
);
1114 r
= asprintf(&s
, "%s %u %u %u %n",
1116 rr
->tlsa
.cert_usage
,
1118 rr
->tlsa
.matching_type
,
1123 r
= base64_append(&s
, n
,
1124 rr
->tlsa
.data
, rr
->tlsa
.data_size
,
1129 r
= asprintf(&ss
, "%s\n"
1130 "%*s-- Cert. usage: %s\n"
1131 "%*s-- Selector: %s\n"
1132 "%*s-- Matching type: %s",
1134 n
- 6, "", cert_usage
,
1135 n
- 6, "", selector
,
1136 n
- 6, "", matching_type
);
1145 case DNS_TYPE_OPENPGPKEY
: {
1148 r
= asprintf(&s
, "%s %n",
1154 r
= base64_append(&s
, n
,
1155 rr
->generic
.data
, rr
->generic
.data_size
,
1163 t
= hexmem(rr
->generic
.data
, rr
->generic
.data_size
);
1167 /* Format as documented in RFC 3597, Section 5 */
1168 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.data_size
, t
);
1178 int dns_resource_record_to_wire_format(DnsResourceRecord
*rr
, bool canonical
) {
1180 DnsPacket packet
= {
1182 .protocol
= DNS_PROTOCOL_DNS
,
1184 .refuse_compression
= true,
1185 .canonical_form
= canonical
,
1193 /* Generates the RR in wire-format, optionally in the
1194 * canonical form as discussed in the DNSSEC RFC 4034, Section
1195 * 6.2. We allocate a throw-away DnsPacket object on the stack
1196 * here, because we need some book-keeping for memory
1197 * management, and can reuse the DnsPacket serializer, that
1198 * can generate the canonical form, too, but also knows label
1199 * compression and suchlike. */
1201 if (rr
->wire_format
&& rr
->wire_format_canonical
== canonical
)
1204 r
= dns_packet_append_rr(&packet
, rr
, &start
, &rds
);
1209 assert(packet
._data
);
1211 free(rr
->wire_format
);
1212 rr
->wire_format
= packet
._data
;
1213 rr
->wire_format_size
= packet
.size
;
1214 rr
->wire_format_rdata_offset
= rds
;
1215 rr
->wire_format_canonical
= canonical
;
1217 packet
._data
= NULL
;
1218 dns_packet_unref(&packet
);
1223 int dns_resource_record_signer(DnsResourceRecord
*rr
, const char **ret
) {
1230 /* Returns the RRset's signer, if it is known. */
1232 if (rr
->n_skip_labels_signer
== (unsigned) -1)
1235 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1236 r
= dns_name_skip(n
, rr
->n_skip_labels_signer
, &n
);
1246 int dns_resource_record_source(DnsResourceRecord
*rr
, const char **ret
) {
1253 /* Returns the RRset's synthesizing source, if it is known. */
1255 if (rr
->n_skip_labels_source
== (unsigned) -1)
1258 n
= DNS_RESOURCE_KEY_NAME(rr
->key
);
1259 r
= dns_name_skip(n
, rr
->n_skip_labels_source
, &n
);
1269 int dns_resource_record_is_signer(DnsResourceRecord
*rr
, const char *zone
) {
1275 r
= dns_resource_record_signer(rr
, &signer
);
1279 return dns_name_equal(zone
, signer
);
1282 int dns_resource_record_is_synthetic(DnsResourceRecord
*rr
) {
1287 /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */
1289 if (rr
->n_skip_labels_source
== (unsigned) -1)
1292 if (rr
->n_skip_labels_source
== 0)
1295 if (rr
->n_skip_labels_source
> 1)
1298 r
= dns_name_startswith(DNS_RESOURCE_KEY_NAME(rr
->key
), "*");
1305 void dns_resource_record_hash_func(const void *i
, struct siphash
*state
) {
1306 const DnsResourceRecord
*rr
= i
;
1310 dns_resource_key_hash_func(rr
->key
, state
);
1312 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
1315 siphash24_compress(&rr
->srv
.priority
, sizeof(rr
->srv
.priority
), state
);
1316 siphash24_compress(&rr
->srv
.weight
, sizeof(rr
->srv
.weight
), state
);
1317 siphash24_compress(&rr
->srv
.port
, sizeof(rr
->srv
.port
), state
);
1318 dns_name_hash_func(rr
->srv
.name
, state
);
1323 case DNS_TYPE_CNAME
:
1324 case DNS_TYPE_DNAME
:
1325 dns_name_hash_func(rr
->ptr
.name
, state
);
1328 case DNS_TYPE_HINFO
:
1329 string_hash_func(rr
->hinfo
.cpu
, state
);
1330 string_hash_func(rr
->hinfo
.os
, state
);
1334 case DNS_TYPE_SPF
: {
1337 LIST_FOREACH(items
, j
, rr
->txt
.items
) {
1338 siphash24_compress(j
->data
, j
->length
, state
);
1340 /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab"
1341 * followed by "". */
1342 siphash24_compress_byte(0, state
);
1348 siphash24_compress(&rr
->a
.in_addr
, sizeof(rr
->a
.in_addr
), state
);
1352 siphash24_compress(&rr
->aaaa
.in6_addr
, sizeof(rr
->aaaa
.in6_addr
), state
);
1356 dns_name_hash_func(rr
->soa
.mname
, state
);
1357 dns_name_hash_func(rr
->soa
.rname
, state
);
1358 siphash24_compress(&rr
->soa
.serial
, sizeof(rr
->soa
.serial
), state
);
1359 siphash24_compress(&rr
->soa
.refresh
, sizeof(rr
->soa
.refresh
), state
);
1360 siphash24_compress(&rr
->soa
.retry
, sizeof(rr
->soa
.retry
), state
);
1361 siphash24_compress(&rr
->soa
.expire
, sizeof(rr
->soa
.expire
), state
);
1362 siphash24_compress(&rr
->soa
.minimum
, sizeof(rr
->soa
.minimum
), state
);
1366 siphash24_compress(&rr
->mx
.priority
, sizeof(rr
->mx
.priority
), state
);
1367 dns_name_hash_func(rr
->mx
.exchange
, state
);
1371 siphash24_compress(&rr
->loc
.version
, sizeof(rr
->loc
.version
), state
);
1372 siphash24_compress(&rr
->loc
.size
, sizeof(rr
->loc
.size
), state
);
1373 siphash24_compress(&rr
->loc
.horiz_pre
, sizeof(rr
->loc
.horiz_pre
), state
);
1374 siphash24_compress(&rr
->loc
.vert_pre
, sizeof(rr
->loc
.vert_pre
), state
);
1375 siphash24_compress(&rr
->loc
.latitude
, sizeof(rr
->loc
.latitude
), state
);
1376 siphash24_compress(&rr
->loc
.longitude
, sizeof(rr
->loc
.longitude
), state
);
1377 siphash24_compress(&rr
->loc
.altitude
, sizeof(rr
->loc
.altitude
), state
);
1380 case DNS_TYPE_SSHFP
:
1381 siphash24_compress(&rr
->sshfp
.algorithm
, sizeof(rr
->sshfp
.algorithm
), state
);
1382 siphash24_compress(&rr
->sshfp
.fptype
, sizeof(rr
->sshfp
.fptype
), state
);
1383 siphash24_compress(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
, state
);
1386 case DNS_TYPE_DNSKEY
:
1387 siphash24_compress(&rr
->dnskey
.flags
, sizeof(rr
->dnskey
.flags
), state
);
1388 siphash24_compress(&rr
->dnskey
.protocol
, sizeof(rr
->dnskey
.protocol
), state
);
1389 siphash24_compress(&rr
->dnskey
.algorithm
, sizeof(rr
->dnskey
.algorithm
), state
);
1390 siphash24_compress(rr
->dnskey
.key
, rr
->dnskey
.key_size
, state
);
1393 case DNS_TYPE_RRSIG
:
1394 siphash24_compress(&rr
->rrsig
.type_covered
, sizeof(rr
->rrsig
.type_covered
), state
);
1395 siphash24_compress(&rr
->rrsig
.algorithm
, sizeof(rr
->rrsig
.algorithm
), state
);
1396 siphash24_compress(&rr
->rrsig
.labels
, sizeof(rr
->rrsig
.labels
), state
);
1397 siphash24_compress(&rr
->rrsig
.original_ttl
, sizeof(rr
->rrsig
.original_ttl
), state
);
1398 siphash24_compress(&rr
->rrsig
.expiration
, sizeof(rr
->rrsig
.expiration
), state
);
1399 siphash24_compress(&rr
->rrsig
.inception
, sizeof(rr
->rrsig
.inception
), state
);
1400 siphash24_compress(&rr
->rrsig
.key_tag
, sizeof(rr
->rrsig
.key_tag
), state
);
1401 dns_name_hash_func(rr
->rrsig
.signer
, state
);
1402 siphash24_compress(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
, state
);
1406 dns_name_hash_func(rr
->nsec
.next_domain_name
, state
);
1407 /* FIXME: we leave out the type bitmap here. Hash
1408 * would be better if we'd take it into account
1413 siphash24_compress(&rr
->ds
.key_tag
, sizeof(rr
->ds
.key_tag
), state
);
1414 siphash24_compress(&rr
->ds
.algorithm
, sizeof(rr
->ds
.algorithm
), state
);
1415 siphash24_compress(&rr
->ds
.digest_type
, sizeof(rr
->ds
.digest_type
), state
);
1416 siphash24_compress(rr
->ds
.digest
, rr
->ds
.digest_size
, state
);
1419 case DNS_TYPE_NSEC3
:
1420 siphash24_compress(&rr
->nsec3
.algorithm
, sizeof(rr
->nsec3
.algorithm
), state
);
1421 siphash24_compress(&rr
->nsec3
.flags
, sizeof(rr
->nsec3
.flags
), state
);
1422 siphash24_compress(&rr
->nsec3
.iterations
, sizeof(rr
->nsec3
.iterations
), state
);
1423 siphash24_compress(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
, state
);
1424 siphash24_compress(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, state
);
1425 /* FIXME: We leave the bitmaps out */
1429 siphash24_compress(&rr
->tlsa
.cert_usage
, sizeof(rr
->tlsa
.cert_usage
), state
);
1430 siphash24_compress(&rr
->tlsa
.selector
, sizeof(rr
->tlsa
.selector
), state
);
1431 siphash24_compress(&rr
->tlsa
.matching_type
, sizeof(rr
->tlsa
.matching_type
), state
);
1432 siphash24_compress(rr
->tlsa
.data
, rr
->tlsa
.data_size
, state
);
1435 case DNS_TYPE_OPENPGPKEY
:
1437 siphash24_compress(rr
->generic
.data
, rr
->generic
.data_size
, state
);
1442 static int dns_resource_record_compare_func(const void *a
, const void *b
) {
1443 const DnsResourceRecord
*x
= a
, *y
= b
;
1446 ret
= dns_resource_key_compare_func(x
->key
, y
->key
);
1450 if (dns_resource_record_equal(x
, y
))
1453 /* This is a bit dirty, we don't implement proper odering, but
1454 * the hashtable doesn't need ordering anyway, hence we don't
1456 return x
< y
? -1 : 1;
1459 const struct hash_ops dns_resource_record_hash_ops
= {
1460 .hash
= dns_resource_record_hash_func
,
1461 .compare
= dns_resource_record_compare_func
,
1464 DnsTxtItem
*dns_txt_item_free_all(DnsTxtItem
*i
) {
1473 return dns_txt_item_free_all(n
);
1476 bool dns_txt_item_equal(DnsTxtItem
*a
, DnsTxtItem
*b
) {
1487 if (a
->length
!= b
->length
)
1490 if (memcmp(a
->data
, b
->data
, a
->length
) != 0)
1493 return dns_txt_item_equal(a
->items_next
, b
->items_next
);
1496 static const char* const dnssec_algorithm_table
[_DNSSEC_ALGORITHM_MAX_DEFINED
] = {
1497 /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
1498 [DNSSEC_ALGORITHM_RSAMD5
] = "RSAMD5",
1499 [DNSSEC_ALGORITHM_DH
] = "DH",
1500 [DNSSEC_ALGORITHM_DSA
] = "DSA",
1501 [DNSSEC_ALGORITHM_ECC
] = "ECC",
1502 [DNSSEC_ALGORITHM_RSASHA1
] = "RSASHA1",
1503 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1
] = "DSA-NSEC3-SHA1",
1504 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1
] = "RSASHA1-NSEC3-SHA1",
1505 [DNSSEC_ALGORITHM_RSASHA256
] = "RSASHA256",
1506 [DNSSEC_ALGORITHM_RSASHA512
] = "RSASHA512",
1507 [DNSSEC_ALGORITHM_ECC_GOST
] = "ECC-GOST",
1508 [DNSSEC_ALGORITHM_ECDSAP256SHA256
] = "ECDSAP256SHA256",
1509 [DNSSEC_ALGORITHM_ECDSAP384SHA384
] = "ECDSAP384SHA384",
1510 [DNSSEC_ALGORITHM_INDIRECT
] = "INDIRECT",
1511 [DNSSEC_ALGORITHM_PRIVATEDNS
] = "PRIVATEDNS",
1512 [DNSSEC_ALGORITHM_PRIVATEOID
] = "PRIVATEOID",
1514 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm
, int, 255);
1516 static const char* const dnssec_digest_table
[_DNSSEC_DIGEST_MAX_DEFINED
] = {
1517 /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
1518 [DNSSEC_DIGEST_SHA1
] = "SHA-1",
1519 [DNSSEC_DIGEST_SHA256
] = "SHA-256",
1520 [DNSSEC_DIGEST_GOST_R_34_11_94
] = "GOST_R_34.11-94",
1521 [DNSSEC_DIGEST_SHA384
] = "SHA-384",
1523 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest
, int, 255);