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"
29 DnsResourceKey
* dns_resource_key_new(uint16_t class, uint16_t type
, const char *name
) {
36 k
= malloc0(sizeof(DnsResourceKey
) + l
+ 1);
44 strcpy((char*) k
+ sizeof(DnsResourceKey
), name
);
49 DnsResourceKey
* dns_resource_key_new_consume(uint16_t class, uint16_t type
, char *name
) {
54 k
= new0(DnsResourceKey
, 1);
66 DnsResourceKey
* dns_resource_key_ref(DnsResourceKey
*k
) {
77 DnsResourceKey
* dns_resource_key_unref(DnsResourceKey
*k
) {
92 int dns_resource_key_equal(const DnsResourceKey
*a
, const DnsResourceKey
*b
) {
95 r
= dns_name_equal(DNS_RESOURCE_KEY_NAME(a
), DNS_RESOURCE_KEY_NAME(b
));
99 if (a
->class != b
->class)
102 if (a
->type
!= b
->type
)
108 int dns_resource_key_match_rr(const DnsResourceKey
*key
, const DnsResourceRecord
*rr
) {
112 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
115 if (rr
->key
->type
!= key
->type
&& key
->type
!= DNS_TYPE_ANY
)
118 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
121 int dns_resource_key_match_cname(const DnsResourceKey
*key
, const DnsResourceRecord
*rr
) {
125 if (rr
->key
->class != key
->class && key
->class != DNS_CLASS_ANY
)
128 if (rr
->key
->type
!= DNS_TYPE_CNAME
)
131 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr
->key
), DNS_RESOURCE_KEY_NAME(key
));
134 unsigned long dns_resource_key_hash_func(const void *i
, const uint8_t hash_key
[HASH_KEY_SIZE
]) {
135 const DnsResourceKey
*k
= i
;
138 ul
= dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k
), hash_key
);
139 ul
= ul
* hash_key
[0] + ul
+ k
->class;
140 ul
= ul
* hash_key
[1] + ul
+ k
->type
;
145 int dns_resource_key_compare_func(const void *a
, const void *b
) {
146 const DnsResourceKey
*x
= a
, *y
= b
;
149 ret
= dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x
), DNS_RESOURCE_KEY_NAME(y
));
153 if (x
->type
< y
->type
)
155 if (x
->type
> y
->type
)
158 if (x
->class < y
->class)
160 if (x
->class > y
->class)
166 int dns_resource_key_to_string(const DnsResourceKey
*key
, char **ret
) {
167 char cbuf
[DECIMAL_STR_MAX(uint16_t)], tbuf
[DECIMAL_STR_MAX(uint16_t)];
171 c
= dns_class_to_string(key
->class);
173 sprintf(cbuf
, "%i", key
->class);
177 t
= dns_type_to_string(key
->type
);
179 sprintf(tbuf
, "%i", key
->type
);
183 s
= strjoin(DNS_RESOURCE_KEY_NAME(key
), " ", c
, " ", t
, NULL
);
191 DnsResourceRecord
* dns_resource_record_new(DnsResourceKey
*key
) {
192 DnsResourceRecord
*rr
;
194 rr
= new0(DnsResourceRecord
, 1);
199 rr
->key
= dns_resource_key_ref(key
);
204 DnsResourceRecord
* dns_resource_record_new_full(uint16_t class, uint16_t type
, const char *name
) {
205 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
207 key
= dns_resource_key_new(class, type
, name
);
211 return dns_resource_record_new(key
);
214 DnsResourceRecord
* dns_resource_record_ref(DnsResourceRecord
*rr
) {
218 assert(rr
->n_ref
> 0);
224 DnsResourceRecord
* dns_resource_record_unref(DnsResourceRecord
*rr
) {
228 assert(rr
->n_ref
> 0);
236 switch(rr
->key
->type
) {
249 strv_free(rr
->txt
.strings
);
256 free(rr
->mx
.exchange
);
263 free(rr
->generic
.data
);
266 dns_resource_key_unref(rr
->key
);
274 int dns_resource_record_new_reverse(DnsResourceRecord
**ret
, int family
, const union in_addr_union
*address
, const char *hostname
) {
275 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
276 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
277 _cleanup_free_
char *ptr
= NULL
;
284 r
= dns_name_reverse(family
, address
, &ptr
);
288 key
= dns_resource_key_new_consume(DNS_CLASS_IN
, DNS_TYPE_PTR
, ptr
);
294 rr
= dns_resource_record_new(key
);
298 rr
->ptr
.name
= strdup(hostname
);
308 int dns_resource_record_equal(const DnsResourceRecord
*a
, const DnsResourceRecord
*b
) {
314 r
= dns_resource_key_equal(a
->key
, b
->key
);
318 switch (a
->key
->type
) {
324 return dns_name_equal(a
->ptr
.name
, b
->ptr
.name
);
327 return strcaseeq(a
->hinfo
.cpu
, b
->hinfo
.cpu
) &&
328 strcaseeq(a
->hinfo
.os
, b
->hinfo
.os
);
330 case DNS_TYPE_SPF
: /* exactly the same as TXT */
334 for (i
= 0; a
->txt
.strings
[i
] || b
->txt
.strings
[i
]; i
++)
335 if (!streq_ptr(a
->txt
.strings
[i
], b
->txt
.strings
[i
]))
341 return memcmp(&a
->a
.in_addr
, &b
->a
.in_addr
, sizeof(struct in_addr
)) == 0;
344 return memcmp(&a
->aaaa
.in6_addr
, &b
->aaaa
.in6_addr
, sizeof(struct in6_addr
)) == 0;
347 r
= dns_name_equal(a
->soa
.mname
, b
->soa
.mname
);
350 r
= dns_name_equal(a
->soa
.rname
, b
->soa
.rname
);
354 return a
->soa
.serial
== b
->soa
.serial
&&
355 a
->soa
.refresh
== b
->soa
.refresh
&&
356 a
->soa
.retry
== b
->soa
.retry
&&
357 a
->soa
.expire
== b
->soa
.expire
&&
358 a
->soa
.minimum
== b
->soa
.minimum
;
360 if (a
->mx
.priority
!= b
->mx
.priority
)
363 return dns_name_equal(a
->mx
.exchange
, b
->mx
.exchange
);
366 assert(a
->loc
.version
== b
->loc
.version
);
368 return a
->loc
.size
== b
->loc
.size
&&
369 a
->loc
.horiz_pre
== b
->loc
.horiz_pre
&&
370 a
->loc
.vert_pre
== b
->loc
.vert_pre
&&
371 a
->loc
.latitude
== b
->loc
.latitude
&&
372 a
->loc
.longitude
== b
->loc
.longitude
&&
373 a
->loc
.altitude
== b
->loc
.altitude
;
376 return a
->generic
.size
== b
->generic
.size
&&
377 memcmp(a
->generic
.data
, b
->generic
.data
, a
->generic
.size
) == 0;
381 static char* format_location(uint32_t latitude
, uint32_t longitude
, uint32_t altitude
,
382 uint8_t size
, uint8_t horiz_pre
, uint8_t vert_pre
) {
384 char NS
= latitude
>= 1U<<31 ? 'N' : 'S';
385 char EW
= longitude
>= 1U<<31 ? 'E' : 'W';
387 int lat
= latitude
>= 1U<<31 ? (int) (latitude
- (1U<<31)) : (int) ((1U<<31) - latitude
);
388 int lon
= longitude
>= 1U<<31 ? (int) (longitude
- (1U<<31)) : (int) ((1U<<31) - longitude
);
389 double alt
= altitude
>= 10000000u ? altitude
- 10000000u : -(double)(10000000u - altitude
);
390 double siz
= (size
>> 4) * exp10((double) (size
& 0xF));
391 double hor
= (horiz_pre
>> 4) * exp10((double) (horiz_pre
& 0xF));
392 double ver
= (vert_pre
>> 4) * exp10((double) (vert_pre
& 0xF));
394 if (asprintf(&s
, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
397 (lat
% 60000) / 1000.,
401 (lon
% 60000) / 1000.,
413 int dns_resource_record_to_string(const DnsResourceRecord
*rr
, char **ret
) {
414 _cleanup_free_
char *k
= NULL
;
420 r
= dns_resource_key_to_string(rr
->key
, &k
);
424 switch (rr
->unparseable
? _DNS_TYPE_INVALID
: rr
->key
->type
) {
430 s
= strjoin(k
, " ", rr
->ptr
.name
, NULL
);
437 s
= strjoin(k
, " ", rr
->hinfo
.cpu
, " ", rr
->hinfo
.os
, NULL
);
442 case DNS_TYPE_SPF
: /* exactly the same as TXT */
444 _cleanup_free_
char *t
;
446 t
= strv_join_quoted(rr
->txt
.strings
);
450 s
= strjoin(k
, " ", t
, NULL
);
458 _cleanup_free_
char *x
= NULL
;
460 r
= in_addr_to_string(AF_INET
, (const union in_addr_union
*) &rr
->a
.in_addr
, &x
);
464 s
= strjoin(k
, " ", x
, NULL
);
470 case DNS_TYPE_AAAA
: {
471 _cleanup_free_
char *x
= NULL
;
473 r
= in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &rr
->aaaa
.in6_addr
, &x
);
477 s
= strjoin(k
, " ", x
, NULL
);
484 r
= asprintf(&s
, "%s %s %s %u %u %u %u %u",
486 strna(rr
->soa
.mname
),
487 strna(rr
->soa
.rname
),
498 r
= asprintf(&s
, "%s %u %s",
507 _cleanup_free_
char *loc
;
508 assert(rr
->loc
.version
== 0);
510 loc
= format_location(rr
->loc
.latitude
,
519 s
= strjoin(k
, " ", loc
, NULL
);
527 _cleanup_free_
char *x
= NULL
;
529 x
= hexmem(rr
->generic
.data
, rr
->generic
.size
);
533 s
= strjoin(k
, " ", x
, NULL
);
543 const char *dns_class_to_string(uint16_t class) {
557 int dns_class_from_string(const char *s
, uint16_t *class) {
561 if (strcaseeq(s
, "IN"))
562 *class = DNS_CLASS_IN
;
563 else if (strcaseeq(s
, "ANY"))
564 *class = DNS_TYPE_ANY
;
571 static const struct {
576 { DNS_TYPE_NS
, "NS" },
577 { DNS_TYPE_CNAME
, "CNAME" },
578 { DNS_TYPE_SOA
, "SOA" },
579 { DNS_TYPE_PTR
, "PTR" },
580 { DNS_TYPE_HINFO
, "HINFO" },
581 { DNS_TYPE_MX
, "MX" },
582 { DNS_TYPE_TXT
, "TXT" },
583 { DNS_TYPE_AAAA
, "AAAA" },
584 { DNS_TYPE_LOC
, "LOC" },
585 { DNS_TYPE_SRV
, "SRV" },
586 { DNS_TYPE_SSHFP
, "SSHFP" },
587 { DNS_TYPE_SPF
, "SPF" },
588 { DNS_TYPE_DNAME
, "DNAME" },
589 { DNS_TYPE_ANY
, "ANY" },
590 { DNS_TYPE_OPT
, "OPT" },
591 { DNS_TYPE_TKEY
, "TKEY" },
592 { DNS_TYPE_TSIG
, "TSIG" },
593 { DNS_TYPE_IXFR
, "IXFR" },
594 { DNS_TYPE_AXFR
, "AXFR" },
597 const char *dns_type_to_string(uint16_t type
) {
600 for (i
= 0; i
< ELEMENTSOF(dns_types
); i
++)
601 if (dns_types
[i
].type
== type
)
602 return dns_types
[i
].name
;
607 int dns_type_from_string(const char *s
, uint16_t *type
) {
613 for (i
= 0; i
< ELEMENTSOF(dns_types
); i
++)
614 if (strcaseeq(dns_types
[i
].name
, s
)) {
615 *type
= dns_types
[i
].type
;