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-util.h"
33 DnsResourceKey
* dns_resource_key_new(uint16_t class, uint16_t type
, const char *name
) {
40 k
= malloc0(sizeof(DnsResourceKey
) + l
+ 1);
48 strcpy((char*) k
+ sizeof(DnsResourceKey
), name
);
53 DnsResourceKey
* dns_resource_key_new_cname(const DnsResourceKey
*key
) {
56 return dns_resource_key_new(key
->class, DNS_TYPE_CNAME
, DNS_RESOURCE_KEY_NAME(key
));
59 DnsResourceKey
* dns_resource_key_new_redirect(const DnsResourceKey
*key
, const DnsResourceRecord
*cname
) {
65 assert(IN_SET(cname
->key
->type
, DNS_TYPE_CNAME
, DNS_TYPE_DNAME
));
67 if (cname
->key
->type
== DNS_TYPE_CNAME
)
68 return dns_resource_key_new(key
->class, key
->type
, cname
->cname
.name
);
71 char *destination
= NULL
;
73 r
= dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(cname
->key
), cname
->dname
.name
, &destination
);
77 return dns_resource_key_ref((DnsResourceKey
*) key
);
79 k
= dns_resource_key_new_consume(key
->class, key
->type
, destination
);
89 DnsResourceKey
* dns_resource_key_new_consume(uint16_t class, uint16_t type
, char *name
) {
94 k
= new0(DnsResourceKey
, 1);
106 DnsResourceKey
* dns_resource_key_ref(DnsResourceKey
*k
) {
111 assert(k
->n_ref
> 0);
117 DnsResourceKey
* dns_resource_key_unref(DnsResourceKey
*k
) {
121 assert(k
->n_ref
> 0);
132 int dns_resource_key_equal(const DnsResourceKey
*a
, const DnsResourceKey
*b
) {
135 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(a
), DNS_RESOURCE_KEY_NAME(b
));
139 if (a
->class != b
->class)
142 if (a
->type
!= b
->type
)
148 int dns_resource_key_match_rr(const DnsResourceKey
*key
, const DnsResourceRecord
*rr
) {
152 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
155 if (rr
->key
->type
!= key
->type
&& key
->type
!= DNS_TYPE_ANY
)
158 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
161 int dns_resource_key_match_cname(const DnsResourceKey
*key
, const DnsResourceRecord
*rr
) {
165 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
168 if (rr
->key
->type
== DNS_TYPE_CNAME
)
169 return dns_name_equal(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(rr
->key
));
170 else if (rr
->key
->type
== DNS_TYPE_DNAME
)
171 return dns_name_endswith(DNS_RESOURCE_KEY_NAME(key
), DNS_RESOURCE_KEY_NAME(rr
->key
));
176 static void dns_resource_key_hash_func(const void *i
, struct siphash
*state
) {
177 const DnsResourceKey
*k
= i
;
181 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k
), state
);
182 siphash24_compress(&k
->class, sizeof(k
->class), state
);
183 siphash24_compress(&k
->type
, sizeof(k
->type
), state
);
186 static int dns_resource_key_compare_func(const void *a
, const void *b
) {
187 const DnsResourceKey
*x
= a
, *y
= b
;
190 ret
= dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x
), DNS_RESOURCE_KEY_NAME(y
));
194 if (x
->type
< y
->type
)
196 if (x
->type
> y
->type
)
199 if (x
->class < y
->class)
201 if (x
->class > y
->class)
207 const struct hash_ops dns_resource_key_hash_ops
= {
208 .hash
= dns_resource_key_hash_func
,
209 .compare
= dns_resource_key_compare_func
212 int dns_resource_key_to_string(const DnsResourceKey
*key
, char **ret
) {
213 char cbuf
[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf
[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
217 c
= dns_class_to_string(key
->class);
219 sprintf(cbuf
, "CLASS%u", key
->class);
223 t
= dns_type_to_string(key
->type
);
225 sprintf(tbuf
, "TYPE%u", key
->type
);
229 if (asprintf(&s
, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key
), c
, t
) < 0)
236 DnsResourceRecord
* dns_resource_record_new(DnsResourceKey
*key
) {
237 DnsResourceRecord
*rr
;
239 rr
= new0(DnsResourceRecord
, 1);
244 rr
->key
= dns_resource_key_ref(key
);
249 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
250 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
252 key
= dns_resource_key_new(class, type
, name
);
256 return dns_resource_record_new(key
);
259 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
263 assert(rr
->n_ref
> 0);
269 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
273 assert(rr
->n_ref
> 0);
281 switch(rr
->key
->type
) {
301 dns_txt_item_free_all(rr
->txt
.items
);
310 free(rr
->mx
.exchange
);
318 free(rr
->sshfp
.fingerprint
);
321 case DNS_TYPE_DNSKEY
:
322 free(rr
->dnskey
.key
);
326 free(rr
->rrsig
.signer
);
327 free(rr
->rrsig
.signature
);
331 free(rr
->nsec
.next_domain_name
);
332 bitmap_free(rr
->nsec
.types
);
336 free(rr
->nsec3
.next_hashed_name
);
337 free(rr
->nsec3
.salt
);
338 bitmap_free(rr
->nsec3
.types
);
347 free(rr
->generic
.data
);
350 dns_resource_key_unref(rr
->key
);
358 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
359 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
360 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
361 _cleanup_free_
char *ptr
= NULL
;
368 r
= dns_name_reverse(family
, address
, &ptr
);
372 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
378 rr
= dns_resource_record_new(key
);
382 rr
->ptr
.name
= strdup(hostname
);
392 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
393 DnsResourceRecord
*rr
;
399 if (family
== AF_INET
) {
401 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
405 rr
->a
.in_addr
= address
->in
;
407 } else if (family
== AF_INET6
) {
409 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
413 rr
->aaaa
.in6_addr
= address
->in6
;
415 return -EAFNOSUPPORT
;
422 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
428 r
= dns_resource_key_equal(a
->key
, b
->key
);
432 if (a
->unparseable
!= b
->unparseable
)
435 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
438 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
442 return a
->srv
.priority
== b
->srv
.priority
&&
443 a
->srv
.weight
== b
->srv
.weight
&&
444 a
->srv
.port
== b
->srv
.port
;
450 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
453 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
454 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
456 case DNS_TYPE_SPF
: /* exactly the same as TXT */
458 return dns_txt_item_equal(a
->txt
.items
, b
->txt
.items
);
461 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
464 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
467 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
470 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
474 return a
->soa
.serial
== b
->soa
.serial
&&
475 a
->soa
.refresh
== b
->soa
.refresh
&&
476 a
->soa
.retry
== b
->soa
.retry
&&
477 a
->soa
.expire
== b
->soa
.expire
&&
478 a
->soa
.minimum
== b
->soa
.minimum
;
481 if (a
->mx
.priority
!= b
->mx
.priority
)
484 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
487 assert(a
->loc
.version
== b
->loc
.version
);
489 return a
->loc
.size
== b
->loc
.size
&&
490 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
491 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
492 a
->loc
.latitude
== b
->loc
.latitude
&&
493 a
->loc
.longitude
== b
->loc
.longitude
&&
494 a
->loc
.altitude
== b
->loc
.altitude
;
497 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
498 a
->ds
.algorithm
== b
->ds
.algorithm
&&
499 a
->ds
.digest_type
== b
->ds
.digest_type
&&
500 a
->ds
.digest_size
== b
->ds
.digest_size
&&
501 memcmp(a
->ds
.digest
, b
->ds
.digest
, a
->ds
.digest_size
) == 0;
504 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
505 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
506 a
->sshfp
.fingerprint_size
== b
->sshfp
.fingerprint_size
&&
507 memcmp(a
->sshfp
.fingerprint
, b
->sshfp
.fingerprint
, a
->sshfp
.fingerprint_size
) == 0;
509 case DNS_TYPE_DNSKEY
:
510 return a
->dnskey
.zone_key_flag
== b
->dnskey
.zone_key_flag
&&
511 a
->dnskey
.sep_flag
== b
->dnskey
.sep_flag
&&
512 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
513 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
514 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
517 /* do the fast comparisons first */
518 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
519 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
520 a
->rrsig
.labels
!= b
->rrsig
.labels
||
521 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
522 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
523 a
->rrsig
.inception
!= b
->rrsig
.inception
||
524 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
525 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
526 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
529 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
532 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
533 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
536 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
537 a
->nsec3
.flags
== b
->nsec3
.flags
&&
538 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
539 a
->nsec3
.salt_size
== b
->nsec3
.salt_size
&&
540 memcmp(a
->nsec3
.salt
, b
->nsec3
.salt
, a
->nsec3
.salt_size
) == 0 &&
541 memcmp(a
->nsec3
.next_hashed_name
, b
->nsec3
.next_hashed_name
, a
->nsec3
.next_hashed_name_size
) == 0 &&
542 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
545 return a
->generic
.size
== b
->generic
.size
&&
546 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
550 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
551 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
553 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
554 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
556 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
557 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
558 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
559 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
560 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
561 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
563 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
566 (lat
% 60000) / 1000.,
570 (lon
% 60000) / 1000.,
581 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
585 assert(l
> strlen("YYYYMMDDHHmmSS"));
587 if (!gmtime_r(&sec
, &tm
))
590 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
596 static char *format_types(Bitmap
*types
) {
597 _cleanup_strv_free_
char **strv
= NULL
;
598 _cleanup_free_
char *str
= NULL
;
603 BITMAP_FOREACH(type
, types
, i
) {
604 if (dns_type_to_string(type
)) {
605 r
= strv_extend(&strv
, dns_type_to_string(type
));
611 r
= asprintf(&t
, "TYPE%u", type
);
615 r
= strv_consume(&strv
, t
);
621 str
= strv_join(strv
, " ");
625 return strjoin("( ", str
, " )", NULL
);
628 static char *format_txt(DnsTxtItem
*first
) {
633 LIST_FOREACH(items
, i
, first
)
634 c
+= i
->length
* 4 + 3;
636 p
= s
= new(char, c
);
640 LIST_FOREACH(items
, i
, first
) {
648 for (j
= 0; j
< i
->length
; j
++) {
649 if (i
->data
[j
] < ' ' || i
->data
[j
] == '"' || i
->data
[j
] >= 127) {
651 *(p
++) = '0' + (i
->data
[j
] / 100);
652 *(p
++) = '0' + ((i
->data
[j
] / 10) % 10);
653 *(p
++) = '0' + (i
->data
[j
] % 10);
665 int dns_resource_record_to_string(const DnsResourceRecord
*rr
, char **ret
) {
666 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
672 r
= dns_resource_key_to_string(rr
->key
, &k
);
676 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
679 r
= asprintf(&s
, "%s %u %u %u %s",
684 strna(rr
->srv
.name
));
693 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
700 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
705 case DNS_TYPE_SPF
: /* exactly the same as TXT */
707 t
= format_txt(rr
->txt
.items
);
711 s
= strjoin(k
, " ", t
, NULL
);
717 _cleanup_free_
char *x
= NULL
;
719 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
723 s
= strjoin(k
, " ", x
, NULL
);
730 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
734 s
= strjoin(k
, " ", t
, NULL
);
740 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
742 strna(rr
->soa
.mname
),
743 strna(rr
->soa
.rname
),
754 r
= asprintf(&s
, "%s %u %s",
763 assert(rr
->loc
.version
== 0);
765 t
= format_location(rr
->loc
.latitude
,
774 s
= strjoin(k
, " ", t
, NULL
);
780 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
784 r
= asprintf(&s
, "%s %u %u %u %s",
795 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
799 r
= asprintf(&s
, "%s %u %u %s",
808 case DNS_TYPE_DNSKEY
: {
811 alg
= dnssec_algorithm_to_string(rr
->dnskey
.algorithm
);
813 t
= base64mem(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
817 r
= asprintf(&s
, "%s %u 3 %.*s%.*u %s",
821 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->dnskey
.algorithm
,
828 case DNS_TYPE_RRSIG
: {
829 const char *type
, *alg
;
830 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
832 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
833 alg
= dnssec_algorithm_to_string(rr
->rrsig
.algorithm
);
835 t
= base64mem(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
839 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
843 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
848 * http://tools.ietf.org/html/rfc3597#section-5 */
850 r
= asprintf(&s
, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
853 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
855 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->rrsig
.algorithm
,
857 rr
->rrsig
.original_ttl
,
869 t
= format_types(rr
->nsec
.types
);
873 r
= asprintf(&s
, "%s %s %s",
875 rr
->nsec
.next_domain_name
,
881 case DNS_TYPE_NSEC3
: {
882 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
884 if (rr
->nsec3
.salt_size
> 0) {
885 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
890 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
894 t
= format_types(rr
->nsec3
.types
);
898 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
902 rr
->nsec3
.iterations
,
903 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
913 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
917 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.size
, t
);
927 const char *dns_class_to_string(uint16_t class) {
941 int dns_class_from_string(const char *s
, uint16_t *class) {
945 if (strcaseeq(s
, "IN"))
946 *class = DNS_CLASS_IN
;
947 else if (strcaseeq(s
, "ANY"))
948 *class = DNS_CLASS_ANY
;
955 DnsTxtItem
*dns_txt_item_free_all(DnsTxtItem
*i
) {
964 return dns_txt_item_free_all(n
);
967 bool dns_txt_item_equal(DnsTxtItem
*a
, DnsTxtItem
*b
) {
975 if (a
->length
!= b
->length
)
978 if (memcmp(a
->data
, b
->data
, a
->length
) != 0)
981 return dns_txt_item_equal(a
->items_next
, b
->items_next
);