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
) {
63 return dns_resource_key_new(key
->class, key
->type
, cname
->cname
.name
);
66 DnsResourceKey
* dns_resource_key_new_consume(uint16_t class, uint16_t type
, char *name
) {
71 k
= new0(DnsResourceKey
, 1);
83 DnsResourceKey
* dns_resource_key_ref(DnsResourceKey
*k
) {
94 DnsResourceKey
* dns_resource_key_unref(DnsResourceKey
*k
) {
109 int dns_resource_key_equal(const DnsResourceKey
*a
, const DnsResourceKey
*b
) {
112 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(a
), DNS_RESOURCE_KEY_NAME(b
));
116 if (a
->class != b
->class)
119 if (a
->type
!= b
->type
)
125 int dns_resource_key_match_rr(const DnsResourceKey
*key
, const DnsResourceRecord
*rr
) {
129 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
132 if (rr
->key
->type
!= key
->type
&& key
->type
!= DNS_TYPE_ANY
)
135 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
138 int dns_resource_key_match_cname(const DnsResourceKey
*key
, const DnsResourceRecord
*rr
) {
142 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
145 if (rr
->key
->type
!= DNS_TYPE_CNAME
)
148 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
151 static void dns_resource_key_hash_func(const void *i
, struct siphash
*state
) {
152 const DnsResourceKey
*k
= i
;
156 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k
), state
);
157 siphash24_compress(&k
->class, sizeof(k
->class), state
);
158 siphash24_compress(&k
->type
, sizeof(k
->type
), state
);
161 static int dns_resource_key_compare_func(const void *a
, const void *b
) {
162 const DnsResourceKey
*x
= a
, *y
= b
;
165 ret
= dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x
), DNS_RESOURCE_KEY_NAME(y
));
169 if (x
->type
< y
->type
)
171 if (x
->type
> y
->type
)
174 if (x
->class < y
->class)
176 if (x
->class > y
->class)
182 const struct hash_ops dns_resource_key_hash_ops
= {
183 .hash
= dns_resource_key_hash_func
,
184 .compare
= dns_resource_key_compare_func
187 int dns_resource_key_to_string(const DnsResourceKey
*key
, char **ret
) {
188 char cbuf
[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf
[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
192 c
= dns_class_to_string(key
->class);
194 sprintf(cbuf
, "CLASS%u", key
->class);
198 t
= dns_type_to_string(key
->type
);
200 sprintf(tbuf
, "TYPE%u", key
->type
);
204 if (asprintf(&s
, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key
), c
, t
) < 0)
211 DnsResourceRecord
* dns_resource_record_new(DnsResourceKey
*key
) {
212 DnsResourceRecord
*rr
;
214 rr
= new0(DnsResourceRecord
, 1);
219 rr
->key
= dns_resource_key_ref(key
);
224 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
225 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
227 key
= dns_resource_key_new(class, type
, name
);
231 return dns_resource_record_new(key
);
234 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
238 assert(rr
->n_ref
> 0);
244 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
248 assert(rr
->n_ref
> 0);
256 switch(rr
->key
->type
) {
276 strv_free(rr
->txt
.strings
);
285 free(rr
->mx
.exchange
);
293 free(rr
->sshfp
.fingerprint
);
296 case DNS_TYPE_DNSKEY
:
297 free(rr
->dnskey
.key
);
301 free(rr
->rrsig
.signer
);
302 free(rr
->rrsig
.signature
);
306 free(rr
->nsec
.next_domain_name
);
307 bitmap_free(rr
->nsec
.types
);
311 free(rr
->nsec3
.next_hashed_name
);
312 free(rr
->nsec3
.salt
);
313 bitmap_free(rr
->nsec3
.types
);
322 free(rr
->generic
.data
);
325 dns_resource_key_unref(rr
->key
);
333 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
334 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
335 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
336 _cleanup_free_
char *ptr
= NULL
;
343 r
= dns_name_reverse(family
, address
, &ptr
);
347 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
353 rr
= dns_resource_record_new(key
);
357 rr
->ptr
.name
= strdup(hostname
);
367 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
368 DnsResourceRecord
*rr
;
374 if (family
== AF_INET
) {
376 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
380 rr
->a
.in_addr
= address
->in
;
382 } else if (family
== AF_INET6
) {
384 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
388 rr
->aaaa
.in6_addr
= address
->in6
;
390 return -EAFNOSUPPORT
;
397 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
403 r
= dns_resource_key_equal(a
->key
, b
->key
);
407 if (a
->unparseable
!= b
->unparseable
)
410 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
413 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
417 return a
->srv
.priority
== b
->srv
.priority
&&
418 a
->srv
.weight
== b
->srv
.weight
&&
419 a
->srv
.port
== b
->srv
.port
;
425 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
428 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
429 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
431 case DNS_TYPE_SPF
: /* exactly the same as TXT */
433 return strv_equal(a
->txt
.strings
, b
->txt
.strings
);
436 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
439 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
442 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
445 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
449 return a
->soa
.serial
== b
->soa
.serial
&&
450 a
->soa
.refresh
== b
->soa
.refresh
&&
451 a
->soa
.retry
== b
->soa
.retry
&&
452 a
->soa
.expire
== b
->soa
.expire
&&
453 a
->soa
.minimum
== b
->soa
.minimum
;
456 if (a
->mx
.priority
!= b
->mx
.priority
)
459 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
462 assert(a
->loc
.version
== b
->loc
.version
);
464 return a
->loc
.size
== b
->loc
.size
&&
465 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
466 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
467 a
->loc
.latitude
== b
->loc
.latitude
&&
468 a
->loc
.longitude
== b
->loc
.longitude
&&
469 a
->loc
.altitude
== b
->loc
.altitude
;
472 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
473 a
->ds
.algorithm
== b
->ds
.algorithm
&&
474 a
->ds
.digest_type
== b
->ds
.digest_type
&&
475 a
->ds
.digest_size
== b
->ds
.digest_size
&&
476 memcmp(a
->ds
.digest
, b
->ds
.digest
, a
->ds
.digest_size
) == 0;
479 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
480 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
481 a
->sshfp
.fingerprint_size
== b
->sshfp
.fingerprint_size
&&
482 memcmp(a
->sshfp
.fingerprint
, b
->sshfp
.fingerprint
, a
->sshfp
.fingerprint_size
) == 0;
484 case DNS_TYPE_DNSKEY
:
485 return a
->dnskey
.zone_key_flag
== b
->dnskey
.zone_key_flag
&&
486 a
->dnskey
.sep_flag
== b
->dnskey
.sep_flag
&&
487 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
488 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
489 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
492 /* do the fast comparisons first */
493 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
494 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
495 a
->rrsig
.labels
!= b
->rrsig
.labels
||
496 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
497 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
498 a
->rrsig
.inception
!= b
->rrsig
.inception
||
499 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
500 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
501 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
504 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
507 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
508 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
511 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
512 a
->nsec3
.flags
== b
->nsec3
.flags
&&
513 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
514 a
->nsec3
.salt_size
== b
->nsec3
.salt_size
&&
515 memcmp(a
->nsec3
.salt
, b
->nsec3
.salt
, a
->nsec3
.salt_size
) == 0 &&
516 memcmp(a
->nsec3
.next_hashed_name
, b
->nsec3
.next_hashed_name
, a
->nsec3
.next_hashed_name_size
) == 0 &&
517 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
520 return a
->generic
.size
== b
->generic
.size
&&
521 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
525 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
526 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
528 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
529 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
531 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
532 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
533 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
534 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
535 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
536 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
538 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
541 (lat
% 60000) / 1000.,
545 (lon
% 60000) / 1000.,
556 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
560 assert(l
> strlen("YYYYMMDDHHmmSS"));
562 if (!gmtime_r(&sec
, &tm
))
565 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
571 static char *format_types(Bitmap
*types
) {
572 _cleanup_strv_free_
char **strv
= NULL
;
573 _cleanup_free_
char *str
= NULL
;
578 BITMAP_FOREACH(type
, types
, i
) {
579 if (dns_type_to_string(type
)) {
580 r
= strv_extend(&strv
, dns_type_to_string(type
));
586 r
= asprintf(&t
, "TYPE%u", type
);
590 r
= strv_consume(&strv
, t
);
596 str
= strv_join(strv
, " ");
600 return strjoin("( ", str
, " )", NULL
);
603 int dns_resource_record_to_string(const DnsResourceRecord
*rr
, char **ret
) {
604 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
610 r
= dns_resource_key_to_string(rr
->key
, &k
);
614 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
617 r
= asprintf(&s
, "%s %u %u %u %s",
622 strna(rr
->srv
.name
));
631 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
638 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
643 case DNS_TYPE_SPF
: /* exactly the same as TXT */
645 t
= strv_join_quoted(rr
->txt
.strings
);
649 s
= strjoin(k
, " ", t
, NULL
);
656 _cleanup_free_
char *x
= NULL
;
658 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
662 s
= strjoin(k
, " ", x
, NULL
);
669 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
673 s
= strjoin(k
, " ", t
, NULL
);
679 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
681 strna(rr
->soa
.mname
),
682 strna(rr
->soa
.rname
),
693 r
= asprintf(&s
, "%s %u %s",
702 assert(rr
->loc
.version
== 0);
704 t
= format_location(rr
->loc
.latitude
,
713 s
= strjoin(k
, " ", t
, NULL
);
719 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
723 r
= asprintf(&s
, "%s %u %u %u %s",
734 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
738 r
= asprintf(&s
, "%s %u %u %s",
747 case DNS_TYPE_DNSKEY
: {
750 alg
= dnssec_algorithm_to_string(rr
->dnskey
.algorithm
);
752 t
= base64mem(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
756 r
= asprintf(&s
, "%s %u 3 %.*s%.*u %s",
760 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->dnskey
.algorithm
,
767 case DNS_TYPE_RRSIG
: {
768 const char *type
, *alg
;
769 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
771 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
772 alg
= dnssec_algorithm_to_string(rr
->rrsig
.algorithm
);
774 t
= base64mem(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
778 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
782 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
787 * http://tools.ietf.org/html/rfc3597#section-5 */
789 r
= asprintf(&s
, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
792 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
794 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->rrsig
.algorithm
,
796 rr
->rrsig
.original_ttl
,
808 t
= format_types(rr
->nsec
.types
);
812 r
= asprintf(&s
, "%s %s %s",
814 rr
->nsec
.next_domain_name
,
820 case DNS_TYPE_NSEC3
: {
821 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
823 if (rr
->nsec3
.salt_size
> 0) {
824 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
829 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
833 t
= format_types(rr
->nsec3
.types
);
837 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
841 rr
->nsec3
.iterations
,
842 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
852 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
856 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.size
, t
);
866 const char *dns_class_to_string(uint16_t class) {
880 int dns_class_from_string(const char *s
, uint16_t *class) {
884 if (strcaseeq(s
, "IN"))
885 *class = DNS_CLASS_IN
;
886 else if (strcaseeq(s
, "ANY"))
887 *class = DNS_CLASS_ANY
;