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/>.
26 #include "dns-domain.h"
27 #include "resolved-dns-rr.h"
28 #include "resolved-dns-packet.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_consume(uint16_t class, uint16_t type
, char *name
) {
56 k
= new0(DnsResourceKey
, 1);
68 DnsResourceKey
* dns_resource_key_ref(DnsResourceKey
*k
) {
79 DnsResourceKey
* dns_resource_key_unref(DnsResourceKey
*k
) {
94 int dns_resource_key_equal(const DnsResourceKey
*a
, const DnsResourceKey
*b
) {
97 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(a
), DNS_RESOURCE_KEY_NAME(b
));
101 if (a
->class != b
->class)
104 if (a
->type
!= b
->type
)
110 int dns_resource_key_match_rr(const DnsResourceKey
*key
, const DnsResourceRecord
*rr
) {
114 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
117 if (rr
->key
->type
!= key
->type
&& key
->type
!= DNS_TYPE_ANY
)
120 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
123 int dns_resource_key_match_cname(const DnsResourceKey
*key
, const DnsResourceRecord
*rr
) {
127 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
130 if (rr
->key
->type
!= DNS_TYPE_CNAME
)
133 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
136 static unsigned long dns_resource_key_hash_func(const void *i
, const uint8_t hash_key
[HASH_KEY_SIZE
]) {
137 const DnsResourceKey
*k
= i
;
140 ul
= dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k
), hash_key
);
141 ul
= ul
* hash_key
[0] + ul
+ k
->class;
142 ul
= ul
* hash_key
[1] + ul
+ k
->type
;
147 static int dns_resource_key_compare_func(const void *a
, const void *b
) {
148 const DnsResourceKey
*x
= a
, *y
= b
;
151 ret
= dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x
), DNS_RESOURCE_KEY_NAME(y
));
155 if (x
->type
< y
->type
)
157 if (x
->type
> y
->type
)
160 if (x
->class < y
->class)
162 if (x
->class > y
->class)
168 const struct hash_ops dns_resource_key_hash_ops
= {
169 .hash
= dns_resource_key_hash_func
,
170 .compare
= dns_resource_key_compare_func
173 int dns_resource_key_to_string(const DnsResourceKey
*key
, char **ret
) {
174 char cbuf
[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf
[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
178 c
= dns_class_to_string(key
->class);
180 sprintf(cbuf
, "CLASS%u", key
->class);
184 t
= dns_type_to_string(key
->type
);
186 sprintf(tbuf
, "TYPE%u", key
->type
);
190 if (asprintf(&s
, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key
), c
, t
) < 0)
197 DnsResourceRecord
* dns_resource_record_new(DnsResourceKey
*key
) {
198 DnsResourceRecord
*rr
;
200 rr
= new0(DnsResourceRecord
, 1);
205 rr
->key
= dns_resource_key_ref(key
);
210 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
211 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
213 key
= dns_resource_key_new(class, type
, name
);
217 return dns_resource_record_new(key
);
220 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
224 assert(rr
->n_ref
> 0);
230 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
234 assert(rr
->n_ref
> 0);
242 switch(rr
->key
->type
) {
262 strv_free(rr
->txt
.strings
);
271 free(rr
->mx
.exchange
);
279 free(rr
->sshfp
.fingerprint
);
282 case DNS_TYPE_DNSKEY
:
283 free(rr
->dnskey
.key
);
287 free(rr
->rrsig
.signer
);
288 free(rr
->rrsig
.signature
);
292 free(rr
->nsec
.next_domain_name
);
293 bitmap_free(rr
->nsec
.types
);
297 free(rr
->nsec3
.next_hashed_name
);
298 free(rr
->nsec3
.salt
);
299 bitmap_free(rr
->nsec3
.types
);
308 free(rr
->generic
.data
);
311 dns_resource_key_unref(rr
->key
);
319 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
320 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
321 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
322 _cleanup_free_
char *ptr
= NULL
;
329 r
= dns_name_reverse(family
, address
, &ptr
);
333 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
339 rr
= dns_resource_record_new(key
);
343 rr
->ptr
.name
= strdup(hostname
);
353 int dns_resource_record_new_address(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *name
) {
354 DnsResourceRecord
*rr
;
360 if (family
== AF_INET
) {
362 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, name
);
366 rr
->a
.in_addr
= address
->in
;
368 } else if (family
== AF_INET6
) {
370 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, name
);
374 rr
->aaaa
.in6_addr
= address
->in6
;
376 return -EAFNOSUPPORT
;
383 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
389 r
= dns_resource_key_equal(a
->key
, b
->key
);
393 if (a
->unparseable
!= b
->unparseable
)
396 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
399 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
403 return a
->srv
.priority
== b
->srv
.priority
&&
404 a
->srv
.weight
== b
->srv
.weight
&&
405 a
->srv
.port
== b
->srv
.port
;
411 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
414 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
415 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
417 case DNS_TYPE_SPF
: /* exactly the same as TXT */
419 return strv_equal(a
->txt
.strings
, b
->txt
.strings
);
422 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
425 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
428 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
431 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
435 return a
->soa
.serial
== b
->soa
.serial
&&
436 a
->soa
.refresh
== b
->soa
.refresh
&&
437 a
->soa
.retry
== b
->soa
.retry
&&
438 a
->soa
.expire
== b
->soa
.expire
&&
439 a
->soa
.minimum
== b
->soa
.minimum
;
442 if (a
->mx
.priority
!= b
->mx
.priority
)
445 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
448 assert(a
->loc
.version
== b
->loc
.version
);
450 return a
->loc
.size
== b
->loc
.size
&&
451 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
452 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
453 a
->loc
.latitude
== b
->loc
.latitude
&&
454 a
->loc
.longitude
== b
->loc
.longitude
&&
455 a
->loc
.altitude
== b
->loc
.altitude
;
458 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
459 a
->ds
.algorithm
== b
->ds
.algorithm
&&
460 a
->ds
.digest_type
== b
->ds
.digest_type
&&
461 a
->ds
.digest_size
== b
->ds
.digest_size
&&
462 memcmp(a
->ds
.digest
, b
->ds
.digest
, a
->ds
.digest_size
) == 0;
465 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
466 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
467 a
->sshfp
.fingerprint_size
== b
->sshfp
.fingerprint_size
&&
468 memcmp(a
->sshfp
.fingerprint
, b
->sshfp
.fingerprint
, a
->sshfp
.fingerprint_size
) == 0;
470 case DNS_TYPE_DNSKEY
:
471 return a
->dnskey
.zone_key_flag
== b
->dnskey
.zone_key_flag
&&
472 a
->dnskey
.sep_flag
== b
->dnskey
.sep_flag
&&
473 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
474 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
475 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
478 /* do the fast comparisons first */
479 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
480 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
481 a
->rrsig
.labels
!= b
->rrsig
.labels
||
482 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
483 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
484 a
->rrsig
.inception
!= b
->rrsig
.inception
||
485 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
486 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
487 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
490 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
493 return dns_name_equal(a
->nsec
.next_domain_name
, b
->nsec
.next_domain_name
) &&
494 bitmap_equal(a
->nsec
.types
, b
->nsec
.types
);
497 return a
->nsec3
.algorithm
== b
->nsec3
.algorithm
&&
498 a
->nsec3
.flags
== b
->nsec3
.flags
&&
499 a
->nsec3
.iterations
== b
->nsec3
.iterations
&&
500 a
->nsec3
.salt_size
== b
->nsec3
.salt_size
&&
501 memcmp(a
->nsec3
.salt
, b
->nsec3
.salt
, a
->nsec3
.salt_size
) == 0 &&
502 memcmp(a
->nsec3
.next_hashed_name
, b
->nsec3
.next_hashed_name
, a
->nsec3
.next_hashed_name_size
) == 0 &&
503 bitmap_equal(a
->nsec3
.types
, b
->nsec3
.types
);
506 return a
->generic
.size
== b
->generic
.size
&&
507 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
511 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
512 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
514 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
515 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
517 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
518 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
519 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
520 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
521 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
522 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
524 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
527 (lat
% 60000) / 1000.,
531 (lon
% 60000) / 1000.,
542 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
546 assert(l
> strlen("YYYYMMDDHHmmSS"));
548 if (!gmtime_r(&sec
, &tm
))
551 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
557 static char *format_types(Bitmap
*types
) {
558 _cleanup_strv_free_
char **strv
= NULL
;
559 _cleanup_free_
char *str
= NULL
;
564 BITMAP_FOREACH(type
, types
, i
) {
565 if (dns_type_to_string(type
)) {
566 r
= strv_extend(&strv
, dns_type_to_string(type
));
572 r
= asprintf(&t
, "TYPE%u", type
);
576 r
= strv_consume(&strv
, t
);
582 str
= strv_join(strv
, " ");
586 return strjoin("( ", str
, " )", NULL
);
589 int dns_resource_record_to_string(const DnsResourceRecord
*rr
, char **ret
) {
590 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
596 r
= dns_resource_key_to_string(rr
->key
, &k
);
600 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
603 r
= asprintf(&s
, "%s %u %u %u %s",
608 strna(rr
->srv
.name
));
617 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
624 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
629 case DNS_TYPE_SPF
: /* exactly the same as TXT */
631 t
= strv_join_quoted(rr
->txt
.strings
);
635 s
= strjoin(k
, " ", t
, NULL
);
642 _cleanup_free_
char *x
= NULL
;
644 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
648 s
= strjoin(k
, " ", x
, NULL
);
655 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
659 s
= strjoin(k
, " ", t
, NULL
);
665 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
667 strna(rr
->soa
.mname
),
668 strna(rr
->soa
.rname
),
679 r
= asprintf(&s
, "%s %u %s",
688 assert(rr
->loc
.version
== 0);
690 t
= format_location(rr
->loc
.latitude
,
699 s
= strjoin(k
, " ", t
, NULL
);
705 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
709 r
= asprintf(&s
, "%s %u %u %u %s",
720 t
= hexmem(rr
->sshfp
.fingerprint
, rr
->sshfp
.fingerprint_size
);
724 r
= asprintf(&s
, "%s %u %u %s",
733 case DNS_TYPE_DNSKEY
: {
736 alg
= dnssec_algorithm_to_string(rr
->dnskey
.algorithm
);
738 t
= base64mem(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
742 r
= asprintf(&s
, "%s %u 3 %.*s%.*u %s",
746 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->dnskey
.algorithm
,
753 case DNS_TYPE_RRSIG
: {
754 const char *type
, *alg
;
755 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
757 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
758 alg
= dnssec_algorithm_to_string(rr
->rrsig
.algorithm
);
760 t
= base64mem(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
764 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
768 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
773 * http://tools.ietf.org/html/rfc3597#section-5 */
775 r
= asprintf(&s
, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
778 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
780 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->rrsig
.algorithm
,
782 rr
->rrsig
.original_ttl
,
794 t
= format_types(rr
->nsec
.types
);
798 r
= asprintf(&s
, "%s %s %s",
800 rr
->nsec
.next_domain_name
,
806 case DNS_TYPE_NSEC3
: {
807 _cleanup_free_
char *salt
= NULL
, *hash
= NULL
;
809 if (rr
->nsec3
.salt_size
> 0) {
810 salt
= hexmem(rr
->nsec3
.salt
, rr
->nsec3
.salt_size
);
815 hash
= base32hexmem(rr
->nsec3
.next_hashed_name
, rr
->nsec3
.next_hashed_name_size
, false);
819 t
= format_types(rr
->nsec3
.types
);
823 r
= asprintf(&s
, "%s %"PRIu8
" %"PRIu8
" %"PRIu16
" %s %s %s",
827 rr
->nsec3
.iterations
,
828 rr
->nsec3
.salt_size
> 0 ? salt
: "-",
838 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
842 r
= asprintf(&s
, "%s \\# %zu %s", k
, rr
->generic
.size
, t
);
852 const char *dns_class_to_string(uint16_t class) {
866 int dns_class_from_string(const char *s
, uint16_t *class) {
870 if (strcaseeq(s
, "IN"))
871 *class = DNS_CLASS_IN
;
872 else if (strcaseeq(s
, "ANY"))
873 *class = DNS_CLASS_ANY
;