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 "resolved-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
[DECIMAL_STR_MAX(uint16_t)], tbuf
[DECIMAL_STR_MAX(uint16_t)];
178 c
= dns_class_to_string(key
->class);
180 sprintf(cbuf
, "%i", key
->class);
184 t
= dns_type_to_string(key
->type
);
186 sprintf(tbuf
, "%i", 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
);
278 case DNS_TYPE_DNSKEY
:
279 free(rr
->dnskey
.key
);
283 free(rr
->rrsig
.signer
);
284 free(rr
->rrsig
.signature
);
293 free(rr
->generic
.data
);
296 dns_resource_key_unref(rr
->key
);
304 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
305 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
306 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
307 _cleanup_free_
char *ptr
= NULL
;
314 r
= dns_name_reverse(family
, address
, &ptr
);
318 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
324 rr
= dns_resource_record_new(key
);
328 rr
->ptr
.name
= strdup(hostname
);
338 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
344 r
= dns_resource_key_equal(a
->key
, b
->key
);
348 if (a
->unparseable
!= b
->unparseable
)
351 switch (a
->unparseable
? _DNS_TYPE_INVALID
: a
->key
->type
) {
354 r
= dns_name_equal(a
->srv
.name
, b
->srv
.name
);
358 return a
->srv
.priority
== b
->srv
.priority
&&
359 a
->srv
.weight
== b
->srv
.weight
&&
360 a
->srv
.port
== b
->srv
.port
;
366 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
369 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
370 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
372 case DNS_TYPE_SPF
: /* exactly the same as TXT */
374 return strv_equal(a
->txt
.strings
, b
->txt
.strings
);
377 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
380 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
383 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
386 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
390 return a
->soa
.serial
== b
->soa
.serial
&&
391 a
->soa
.refresh
== b
->soa
.refresh
&&
392 a
->soa
.retry
== b
->soa
.retry
&&
393 a
->soa
.expire
== b
->soa
.expire
&&
394 a
->soa
.minimum
== b
->soa
.minimum
;
397 if (a
->mx
.priority
!= b
->mx
.priority
)
400 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
403 assert(a
->loc
.version
== b
->loc
.version
);
405 return a
->loc
.size
== b
->loc
.size
&&
406 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
407 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
408 a
->loc
.latitude
== b
->loc
.latitude
&&
409 a
->loc
.longitude
== b
->loc
.longitude
&&
410 a
->loc
.altitude
== b
->loc
.altitude
;
413 return a
->sshfp
.algorithm
== b
->sshfp
.algorithm
&&
414 a
->sshfp
.fptype
== b
->sshfp
.fptype
&&
415 a
->sshfp
.key_size
== b
->sshfp
.key_size
&&
416 memcmp(a
->sshfp
.key
, b
->sshfp
.key
, a
->sshfp
.key_size
) == 0;
418 case DNS_TYPE_DNSKEY
:
419 return a
->dnskey
.zone_key_flag
== b
->dnskey
.zone_key_flag
&&
420 a
->dnskey
.sep_flag
== b
->dnskey
.sep_flag
&&
421 a
->dnskey
.algorithm
== b
->dnskey
.algorithm
&&
422 a
->dnskey
.key_size
== b
->dnskey
.key_size
&&
423 memcmp(a
->dnskey
.key
, b
->dnskey
.key
, a
->dnskey
.key_size
) == 0;
426 /* do the fast comparisons first */
427 if (a
->rrsig
.type_covered
!= b
->rrsig
.type_covered
||
428 a
->rrsig
.algorithm
!= b
->rrsig
.algorithm
||
429 a
->rrsig
.labels
!= b
->rrsig
.labels
||
430 a
->rrsig
.original_ttl
!= b
->rrsig
.original_ttl
||
431 a
->rrsig
.expiration
!= b
->rrsig
.expiration
||
432 a
->rrsig
.inception
!= b
->rrsig
.inception
||
433 a
->rrsig
.key_tag
!= b
->rrsig
.key_tag
||
434 a
->rrsig
.signature_size
!= b
->rrsig
.signature_size
||
435 memcmp(a
->rrsig
.signature
, b
->rrsig
.signature
, a
->rrsig
.signature_size
) != 0)
438 return dns_name_equal(a
->rrsig
.signer
, b
->rrsig
.signer
);
441 return a
->generic
.size
== b
->generic
.size
&&
442 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
446 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
447 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
449 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
450 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
452 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
453 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
454 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
455 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
456 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
457 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
459 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
462 (lat
% 60000) / 1000.,
466 (lon
% 60000) / 1000.,
477 int dns_resource_record_to_string(const DnsResourceRecord
*rr
, char **ret
) {
478 _cleanup_free_
char *k
= NULL
, *t
= NULL
;
484 r
= dns_resource_key_to_string(rr
->key
, &k
);
488 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
491 r
= asprintf(&s
, "%s %u %u %u %s",
496 strna(rr
->srv
.name
));
505 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
512 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
517 case DNS_TYPE_SPF
: /* exactly the same as TXT */
519 t
= strv_join_quoted(rr
->txt
.strings
);
523 s
= strjoin(k
, " ", t
, NULL
);
530 _cleanup_free_
char *x
= NULL
;
532 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
536 s
= strjoin(k
, " ", x
, NULL
);
543 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &t
);
547 s
= strjoin(k
, " ", t
, NULL
);
553 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
555 strna(rr
->soa
.mname
),
556 strna(rr
->soa
.rname
),
567 r
= asprintf(&s
, "%s %u %s",
576 assert(rr
->loc
.version
== 0);
578 t
= format_location(rr
->loc
.latitude
,
587 s
= strjoin(k
, " ", t
, NULL
);
593 t
= hexmem(rr
->sshfp
.key
, rr
->sshfp
.key_size
);
597 r
= asprintf(&s
, "%s %u %u %s",
606 case DNS_TYPE_DNSKEY
: {
609 alg
= dnssec_algorithm_to_string(rr
->dnskey
.algorithm
);
611 t
= hexmem(rr
->dnskey
.key
, rr
->dnskey
.key_size
);
615 r
= asprintf(&s
, "%s %u 3 %.*s%.*u %s",
619 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->dnskey
.algorithm
,
626 case DNS_TYPE_RRSIG
: {
627 const char *type
, *alg
;
629 type
= dns_type_to_string(rr
->rrsig
.type_covered
);
630 alg
= dnssec_algorithm_to_string(rr
->rrsig
.algorithm
);
632 t
= hexmem(rr
->rrsig
.signature
, rr
->rrsig
.signature_size
);
637 * http://tools.ietf.org/html/rfc3597#section-5 */
639 r
= asprintf(&s
, "%s %s%.*u %.*s%.*u %u %u %u %u %u %s %s",
642 type
? 0 : 1, type
? 0u : (unsigned) rr
->rrsig
.type_covered
,
644 alg
? 0 : 1, alg
? 0u : (unsigned) rr
->rrsig
.algorithm
,
646 rr
->rrsig
.original_ttl
,
647 rr
->rrsig
.expiration
,
658 t
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
662 s
= strjoin(k
, " ", t
, NULL
);
672 const char *dns_class_to_string(uint16_t class) {
686 int dns_class_from_string(const char *s
, uint16_t *class) {
690 if (strcaseeq(s
, "IN"))
691 *class = DNS_CLASS_IN
;
692 else if (strcaseeq(s
, "ANY"))
693 *class = DNS_TYPE_ANY
;