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
);
282 case DNS_TYPE_DNSKEY
:
283 free(rr
->dnskey
.key
);
287 free(rr
->rrsig
.signer
);
288 free(rr
->rrsig
.signature
);
297 free(rr
->generic
.data
);
300 dns_resource_key_unref(rr
->key
);
308 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
309 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
310 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
311 _cleanup_free_
char *ptr
= NULL
;
318 r
= dns_name_reverse(family
, address
, &ptr
);
322 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
328 rr
= dns_resource_record_new(key
);
332 rr
->ptr
.name
= strdup(hostname
);
342 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
348 r
= dns_resource_key_equal(a
->key
, b
->key
);
352 if (a
->unparseable
!= b
->unparseable
)
355 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
358 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
362 return a
->srv
.priority
== b
->srv
.priority
&&
363 a
->srv
.weight
== b
->srv
.weight
&&
364 a
->srv
.port
== b
->srv
.port
;
370 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
373 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
374 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
376 case DNS_TYPE_SPF
: /* exactly the same as TXT */
378 return strv_equal(a
->txt
.strings
, b
->txt
.strings
);
381 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
384 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
387 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
390 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
394 return a
->soa
.serial
== b
->soa
.serial
&&
395 a
->soa
.refresh
== b
->soa
.refresh
&&
396 a
->soa
.retry
== b
->soa
.retry
&&
397 a
->soa
.expire
== b
->soa
.expire
&&
398 a
->soa
.minimum
== b
->soa
.minimum
;
401 if (a
->mx
.priority
!= b
->mx
.priority
)
404 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
407 assert(a
->loc
.version
== b
->loc
.version
);
409 return a
->loc
.size
== b
->loc
.size
&&
410 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
411 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
412 a
->loc
.latitude
== b
->loc
.latitude
&&
413 a
->loc
.longitude
== b
->loc
.longitude
&&
414 a
->loc
.altitude
== b
->loc
.altitude
;
417 return a
->ds
.key_tag
== b
->ds
.key_tag
&&
418 a
->ds
.algorithm
== b
->ds
.algorithm
&&
419 a
->ds
.digest_type
== b
->ds
.digest_type
&&
420 a
->ds
.digest_size
== b
->ds
.digest_size
&&
421 memcmp(a
->ds
.digest
, b
->ds
.digest
, a
->ds
.digest_size
) == 0;
424 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
425 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
426 a
->sshfp
.key_size
== b
->sshfp
.key_size
&&
427 memcmp(a
->sshfp
.key
, b
->sshfp
.key
, a
->sshfp
.key_size
) == 0;
429 case DNS_TYPE_DNSKEY
:
430 return a
->dnskey
.zone_key_flag
== b
->dnskey
.zone_key_flag
&&
431 a
->dnskey
.sep_flag
== b
->dnskey
.sep_flag
&&
432 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
433 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
434 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
437 /* do the fast comparisons first */
438 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
439 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
440 a
->rrsig
.labels
!= b
->rrsig
.labels
||
441 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
442 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
443 a
->rrsig
.inception
!= b
->rrsig
.inception
||
444 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
445 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
446 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
449 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
452 return a
->generic
.size
== b
->generic
.size
&&
453 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
457 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
458 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
460 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
461 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
463 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
464 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
465 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
466 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
467 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
468 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
470 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
473 (lat
% 60000) / 1000.,
477 (lon
% 60000) / 1000.,
488 static int format_timestamp_dns(char *buf
, size_t l
, time_t sec
) {
492 assert(l
> strlen("YYYYMMDDHHmmSS"));
494 if (!gmtime_r(&sec
, &tm
))
497 if (strftime(buf
, l
, "%Y%m%d%H%M%S", &tm
) <= 0)
503 int dns_resource_record_to_string(const DnsResourceRecord
*rr
, char **ret
) {
504 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
510 r
= dns_resource_key_to_string(rr
->key
, &k
);
514 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
517 r
= asprintf(&s
, "%s %u %u %u %s",
522 strna(rr
->srv
.name
));
531 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
538 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
543 case DNS_TYPE_SPF
: /* exactly the same as TXT */
545 t
= strv_join_quoted(rr
->txt
.strings
);
549 s
= strjoin(k
, " ", t
, NULL
);
556 _cleanup_free_
char *x
= NULL
;
558 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
562 s
= strjoin(k
, " ", x
, NULL
);
569 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
573 s
= strjoin(k
, " ", t
, NULL
);
579 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
581 strna(rr
->soa
.mname
),
582 strna(rr
->soa
.rname
),
593 r
= asprintf(&s
, "%s %u %s",
602 assert(rr
->loc
.version
== 0);
604 t
= format_location(rr
->loc
.latitude
,
613 s
= strjoin(k
, " ", t
, NULL
);
619 t
= hexmem(rr
->ds
.digest
, rr
->ds
.digest_size
);
623 r
= asprintf(&s
, "%s %u %u %u %s",
634 t
= hexmem(rr
->sshfp
.key
, rr
->sshfp
.key_size
);
638 r
= asprintf(&s
, "%s %u %u %s",
647 case DNS_TYPE_DNSKEY
: {
650 alg
= dnssec_algorithm_to_string(rr
->dnskey
.algorithm
);
652 t
= base64mem(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
656 r
= asprintf(&s
, "%s %u 3 %.*s%.*u %s",
660 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->dnskey
.algorithm
,
667 case DNS_TYPE_RRSIG
: {
668 const char *type
, *alg
;
669 char expiration
[strlen("YYYYMMDDHHmmSS") + 1], inception
[strlen("YYYYMMDDHHmmSS") + 1];
671 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
672 alg
= dnssec_algorithm_to_string(rr
->rrsig
.algorithm
);
674 t
= base64mem(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
678 r
= format_timestamp_dns(expiration
, sizeof(expiration
), rr
->rrsig
.expiration
);
682 r
= format_timestamp_dns(inception
, sizeof(inception
), rr
->rrsig
.inception
);
687 * http://tools.ietf.org/html/rfc3597#section-5 */
689 r
= asprintf(&s
, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
692 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
694 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->rrsig
.algorithm
,
696 rr
->rrsig
.original_ttl
,
708 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
712 r
= asprintf(&s
, "%s \\# %"PRIu8
" %s", k
, rr
->generic
.size
, t
);
722 const char *dns_class_to_string(uint16_t class) {
736 int dns_class_from_string(const char *s
, uint16_t *class) {
740 if (strcaseeq(s
, "IN"))
741 *class = DNS_CLASS_IN
;
742 else if (strcaseeq(s
, "ANY"))
743 *class = DNS_TYPE_ANY
;