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 "dns-domain.h"
26 #include "resolved-dns-packet.h"
27 #include "string-util.h"
29 #include "resolved-dns-rr.h"
31 DnsResourceKey
* dns_resource_key_new(uint16_t class, uint16_t type
, const char *name
) {
38 k
= malloc0(sizeof(DnsResourceKey
) + l
+ 1);
46 strcpy((char*) k
+ sizeof(DnsResourceKey
), name
);
51 DnsResourceKey
* dns_resource_key_new_cname(const DnsResourceKey
*key
) {
54 return dns_resource_key_new(key
->class, DNS_TYPE_CNAME
, DNS_RESOURCE_KEY_NAME(key
));
57 DnsResourceKey
* dns_resource_key_new_redirect(const DnsResourceKey
*key
, const DnsResourceRecord
*cname
) {
61 return dns_resource_key_new(key
->class, key
->type
, cname
->cname
.name
);
64 DnsResourceKey
* dns_resource_key_new_consume(uint16_t class, uint16_t type
, char *name
) {
69 k
= new0(DnsResourceKey
, 1);
81 DnsResourceKey
* dns_resource_key_ref(DnsResourceKey
*k
) {
92 DnsResourceKey
* dns_resource_key_unref(DnsResourceKey
*k
) {
107 int dns_resource_key_equal(const DnsResourceKey
*a
, const DnsResourceKey
*b
) {
110 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(a
), DNS_RESOURCE_KEY_NAME(b
));
114 if (a
->class != b
->class)
117 if (a
->type
!= b
->type
)
123 int dns_resource_key_match_rr(const DnsResourceKey
*key
, const DnsResourceRecord
*rr
) {
127 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
130 if (rr
->key
->type
!= key
->type
&& key
->type
!= DNS_TYPE_ANY
)
133 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
136 int dns_resource_key_match_cname(const DnsResourceKey
*key
, const DnsResourceRecord
*rr
) {
140 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
143 if (rr
->key
->type
!= DNS_TYPE_CNAME
)
146 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
149 static void dns_resource_key_hash_func(const void *i
, struct siphash
*state
) {
150 const DnsResourceKey
*k
= i
;
154 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k
), state
);
155 siphash24_compress(&k
->class, sizeof(k
->class), state
);
156 siphash24_compress(&k
->type
, sizeof(k
->type
), state
);
159 static int dns_resource_key_compare_func(const void *a
, const void *b
) {
160 const DnsResourceKey
*x
= a
, *y
= b
;
163 ret
= dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x
), DNS_RESOURCE_KEY_NAME(y
));
167 if (x
->type
< y
->type
)
169 if (x
->type
> y
->type
)
172 if (x
->class < y
->class)
174 if (x
->class > y
->class)
180 const struct hash_ops dns_resource_key_hash_ops
= {
181 .hash
= dns_resource_key_hash_func
,
182 .compare
= dns_resource_key_compare_func
185 int dns_resource_key_to_string(const DnsResourceKey
*key
, char **ret
) {
186 char cbuf
[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf
[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
190 c
= dns_class_to_string(key
->class);
192 sprintf(cbuf
, "CLASS%u", key
->class);
196 t
= dns_type_to_string(key
->type
);
198 sprintf(tbuf
, "TYPE%u", key
->type
);
202 if (asprintf(&s
, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key
), c
, t
) < 0)
209 DnsResourceRecord
* dns_resource_record_new(DnsResourceKey
*key
) {
210 DnsResourceRecord
*rr
;
212 rr
= new0(DnsResourceRecord
, 1);
217 rr
->key
= dns_resource_key_ref(key
);
222 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
223 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
225 key
= dns_resource_key_new(class, type
, name
);
229 return dns_resource_record_new(key
);
232 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
236 assert(rr
->n_ref
> 0);
242 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
246 assert(rr
->n_ref
> 0);
254 switch(rr
->key
->type
) {
274 strv_free(rr
->txt
.strings
);
283 free(rr
->mx
.exchange
);
291 free(rr
->sshfp
.fingerprint
);
294 case DNS_TYPE_DNSKEY
:
295 free(rr
->dnskey
.key
);
299 free(rr
->rrsig
.signer
);
300 free(rr
->rrsig
.signature
);
304 free(rr
->nsec
.next_domain_name
);
305 bitmap_free(rr
->nsec
.types
);
309 free(rr
->nsec3
.next_hashed_name
);
310 free(rr
->nsec3
.salt
);
311 bitmap_free(rr
->nsec3
.types
);
320 free(rr
->generic
.data
);
323 dns_resource_key_unref(rr
->key
);
331 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
332 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
333 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
334 _cleanup_free_
char *ptr
= NULL
;
341 r
= dns_name_reverse(family
, address
, &ptr
);
345 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
351 rr
= dns_resource_record_new(key
);
355 rr
->ptr
.name
= strdup(hostname
);
365 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
366 DnsResourceRecord
*rr
;
372 if (family
== AF_INET
) {
374 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
378 rr
->a
.in_addr
= address
->in
;
380 } else if (family
== AF_INET6
) {
382 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
386 rr
->aaaa
.in6_addr
= address
->in6
;
388 return -EAFNOSUPPORT
;
395 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
401 r
= dns_resource_key_equal(a
->key
, b
->key
);
405 if (a
->unparseable
!= b
->unparseable
)
408 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
411 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
415 return a
->srv
.priority
== b
->srv
.priority
&&
416 a
->srv
.weight
== b
->srv
.weight
&&
417 a
->srv
.port
== b
->srv
.port
;
423 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
426 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
427 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
429 case DNS_TYPE_SPF
: /* exactly the same as TXT */
431 return strv_equal(a
->txt
.strings
, b
->txt
.strings
);
434 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
437 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
440 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
443 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
447 return a
->soa
.serial
== b
->soa
.serial
&&
448 a
->soa
.refresh
== b
->soa
.refresh
&&
449 a
->soa
.retry
== b
->soa
.retry
&&
450 a
->soa
.expire
== b
->soa
.expire
&&
451 a
->soa
.minimum
== b
->soa
.minimum
;
454 if (a
->mx
.priority
!= b
->mx
.priority
)
457 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
460 assert(a
->loc
.version
== b
->loc
.version
);
462 return a
->loc
.size
== b
->loc
.size
&&
463 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
464 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
465 a
->loc
.latitude
== b
->loc
.latitude
&&
466 a
->loc
.longitude
== b
->loc
.longitude
&&
467 a
->loc
.altitude
== b
->loc
.altitude
;
470 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
471 a
->ds
.algorithm
== b
->ds
.algorithm
&&
472 a
->ds
.digest_type
== b
->ds
.digest_type
&&
473 a
->ds
.digest_size
== b
->ds
.digest_size
&&
474 memcmp(a
->ds
.digest
, b
->ds
.digest
, a
->ds
.digest_size
) == 0;
477 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
478 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
479 a
->sshfp
.fingerprint_size
== b
->sshfp
.fingerprint_size
&&
480 memcmp(a
->sshfp
.fingerprint
, b
->sshfp
.fingerprint
, a
->sshfp
.fingerprint_size
) == 0;
482 case DNS_TYPE_DNSKEY
:
483 return a
->dnskey
.zone_key_flag
== b
->dnskey
.zone_key_flag
&&
484 a
->dnskey
.sep_flag
== b
->dnskey
.sep_flag
&&
485 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
486 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
487 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
490 /* do the fast comparisons first */
491 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
492 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
493 a
->rrsig
.labels
!= b
->rrsig
.labels
||
494 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
495 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
496 a
->rrsig
.inception
!= b
->rrsig
.inception
||
497 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
498 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
499 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
502 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
505 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
506 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
509 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
510 a
->nsec3
.flags
== b
->nsec3
.flags
&&
511 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
512 a
->nsec3
.salt_size
== b
->nsec3
.salt_size
&&
513 memcmp(a
->nsec3
.salt
, b
->nsec3
.salt
, a
->nsec3
.salt_size
) == 0 &&
514 memcmp(a
->nsec3
.next_hashed_name
, b
->nsec3
.next_hashed_name
, a
->nsec3
.next_hashed_name_size
) == 0 &&
515 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
518 return a
->generic
.size
== b
->generic
.size
&&
519 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
523 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
524 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
526 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
527 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
529 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
530 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
531 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
532 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
533 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
534 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
536 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
539 (lat
% 60000) / 1000.,
543 (lon
% 60000) / 1000.,
554 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
558 assert(l
> strlen("YYYYMMDDHHmmSS"));
560 if (!gmtime_r(&sec
, &tm
))
563 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
569 static char *format_types(Bitmap
*types
) {
570 _cleanup_strv_free_
char **strv
= NULL
;
571 _cleanup_free_
char *str
= NULL
;
576 BITMAP_FOREACH(type
, types
, i
) {
577 if (dns_type_to_string(type
)) {
578 r
= strv_extend(&strv
, dns_type_to_string(type
));
584 r
= asprintf(&t
, "TYPE%u", type
);
588 r
= strv_consume(&strv
, t
);
594 str
= strv_join(strv
, " ");
598 return strjoin("( ", str
, " )", NULL
);
601 int dns_resource_record_to_string(const DnsResourceRecord
*rr
, char **ret
) {
602 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
608 r
= dns_resource_key_to_string(rr
->key
, &k
);
612 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
615 r
= asprintf(&s
, "%s %u %u %u %s",
620 strna(rr
->srv
.name
));
629 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
636 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
641 case DNS_TYPE_SPF
: /* exactly the same as TXT */
643 t
= strv_join_quoted(rr
->txt
.strings
);
647 s
= strjoin(k
, " ", t
, NULL
);
654 _cleanup_free_
char *x
= NULL
;
656 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
660 s
= strjoin(k
, " ", x
, NULL
);
667 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
671 s
= strjoin(k
, " ", t
, NULL
);
677 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
679 strna(rr
->soa
.mname
),
680 strna(rr
->soa
.rname
),
691 r
= asprintf(&s
, "%s %u %s",
700 assert(rr
->loc
.version
== 0);
702 t
= format_location(rr
->loc
.latitude
,
711 s
= strjoin(k
, " ", t
, NULL
);
717 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
721 r
= asprintf(&s
, "%s %u %u %u %s",
732 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
736 r
= asprintf(&s
, "%s %u %u %s",
745 case DNS_TYPE_DNSKEY
: {
748 alg
= dnssec_algorithm_to_string(rr
->dnskey
.algorithm
);
750 t
= base64mem(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
754 r
= asprintf(&s
, "%s %u 3 %.*s%.*u %s",
758 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->dnskey
.algorithm
,
765 case DNS_TYPE_RRSIG
: {
766 const char *type
, *alg
;
767 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
769 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
770 alg
= dnssec_algorithm_to_string(rr
->rrsig
.algorithm
);
772 t
= base64mem(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
776 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
780 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
785 * http://tools.ietf.org/html/rfc3597#section-5 */
787 r
= asprintf(&s
, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
790 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
792 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->rrsig
.algorithm
,
794 rr
->rrsig
.original_ttl
,
806 t
= format_types(rr
->nsec
.types
);
810 r
= asprintf(&s
, "%s %s %s",
812 rr
->nsec
.next_domain_name
,
818 case DNS_TYPE_NSEC3
: {
819 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
821 if (rr
->nsec3
.salt_size
> 0) {
822 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
827 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
831 t
= format_types(rr
->nsec3
.types
);
835 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
839 rr
->nsec3
.iterations
,
840 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
850 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
854 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.size
, t
);
864 const char *dns_class_to_string(uint16_t class) {
878 int dns_class_from_string(const char *s
, uint16_t *class) {
882 if (strcaseeq(s
, "IN"))
883 *class = DNS_CLASS_IN
;
884 else if (strcaseeq(s
, "ANY"))
885 *class = DNS_CLASS_ANY
;