]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-rr.c
resolved: rework how we allow allow queries to be dispatched to scopes
[thirdparty/systemd.git] / src / resolve / resolved-dns-rr.c
CommitLineData
74b2466e
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
0dae31d4
ZJS
22#include <math.h>
23
b5efdb8a 24#include "alloc-util.h"
4ad7f276 25#include "dns-domain.h"
7263f724 26#include "dns-type.h"
e4e73a63 27#include "hexdecoct.h"
07630cea 28#include "resolved-dns-packet.h"
e4e73a63 29#include "resolved-dns-rr.h"
8730bccf 30#include "string-table.h"
07630cea
LP
31#include "string-util.h"
32#include "strv.h"
74b2466e 33
faa133f3
LP
34DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
35 DnsResourceKey *k;
36 size_t l;
74b2466e 37
faa133f3
LP
38 assert(name);
39
40 l = strlen(name);
41 k = malloc0(sizeof(DnsResourceKey) + l + 1);
42 if (!k)
43 return NULL;
44
45 k->n_ref = 1;
46 k->class = class;
47 k->type = type;
48
49 strcpy((char*) k + sizeof(DnsResourceKey), name);
50
51 return k;
52}
53
36d9205d 54DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) {
58db254a
LP
55 int r;
56
36d9205d
TG
57 assert(key);
58 assert(cname);
59
58db254a
LP
60 assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME));
61
62 if (cname->key->type == DNS_TYPE_CNAME)
63 return dns_resource_key_new(key->class, key->type, cname->cname.name);
64 else {
65 DnsResourceKey *k;
66 char *destination = NULL;
67
68 r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination);
69 if (r < 0)
70 return NULL;
71 if (r == 0)
72 return dns_resource_key_ref((DnsResourceKey*) key);
73
74 k = dns_resource_key_new_consume(key->class, key->type, destination);
75 if (!k) {
76 free(destination);
77 return NULL;
78 }
79
80 return k;
81 }
36d9205d
TG
82}
83
801ad6a6
LP
84int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name) {
85 DnsResourceKey *new_key;
86 char *joined;
87 int r;
88
89 assert(ret);
90 assert(key);
91 assert(name);
92
dc477e73 93 if (dns_name_is_root(name)) {
801ad6a6
LP
94 *ret = dns_resource_key_ref(key);
95 return 0;
96 }
97
98 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), name, &joined);
99 if (r < 0)
100 return r;
101
102 new_key = dns_resource_key_new_consume(key->class, key->type, joined);
103 if (!new_key) {
104 free(joined);
105 return -ENOMEM;
106 }
107
108 *ret = new_key;
109 return 0;
110}
111
faa133f3
LP
112DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
113 DnsResourceKey *k;
114
115 assert(name);
116
117 k = new0(DnsResourceKey, 1);
118 if (!k)
119 return NULL;
120
121 k->n_ref = 1;
122 k->class = class;
123 k->type = type;
124 k->_name = name;
125
126 return k;
127}
128
129DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
130
131 if (!k)
132 return NULL;
133
1b4f6e79
LP
134 /* Static/const keys created with DNS_RESOURCE_KEY_CONST will
135 * set this to -1, they should not be reffed/unreffed */
136 assert(k->n_ref != (unsigned) -1);
137
faa133f3
LP
138 assert(k->n_ref > 0);
139 k->n_ref++;
140
141 return k;
142}
143
144DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
145 if (!k)
146 return NULL;
147
1b4f6e79 148 assert(k->n_ref != (unsigned) -1);
faa133f3
LP
149 assert(k->n_ref > 0);
150
151 if (k->n_ref == 1) {
152 free(k->_name);
153 free(k);
154 } else
155 k->n_ref--;
156
157 return NULL;
158}
159
28b9b764
LP
160bool dns_resource_key_is_address(const DnsResourceKey *key) {
161 assert(key);
162
163 /* Check if this is an A or AAAA resource key */
164
165 return key->class == DNS_CLASS_IN && IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_AAAA);
166}
167
faa133f3
LP
168int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
169 int r;
170
171 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
172 if (r <= 0)
173 return r;
174
175 if (a->class != b->class)
176 return 0;
177
178 if (a->type != b->type)
179 return 0;
180
181 return 1;
182}
183
801ad6a6
LP
184int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain) {
185 int r;
186
faa133f3
LP
187 assert(key);
188 assert(rr);
189
801ad6a6
LP
190 /* Checks if an rr matches the specified key. If a search
191 * domain is specified, it will also be checked if the key
192 * with the search domain suffixed might match the RR. */
193
faa133f3
LP
194 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
195 return 0;
196
197 if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
198 return 0;
199
801ad6a6
LP
200 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
201 if (r != 0)
202 return r;
203
204 if (search_domain) {
205 _cleanup_free_ char *joined = NULL;
206
207 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
208 if (r < 0)
209 return r;
210
211 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), joined);
212 }
213
214 return 0;
faa133f3
LP
215}
216
801ad6a6
LP
217int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain) {
218 int r;
219
faa133f3
LP
220 assert(key);
221 assert(rr);
222
223 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
224 return 0;
225
58db254a 226 if (rr->key->type == DNS_TYPE_CNAME)
801ad6a6 227 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(rr->key));
58db254a 228 else if (rr->key->type == DNS_TYPE_DNAME)
801ad6a6 229 r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(rr->key));
58db254a 230 else
faa133f3 231 return 0;
801ad6a6
LP
232
233 if (r != 0)
234 return r;
235
236 if (search_domain) {
237 _cleanup_free_ char *joined = NULL;
238
239 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
240 if (r < 0)
241 return r;
242
243 if (rr->key->type == DNS_TYPE_CNAME)
244 return dns_name_equal(joined, DNS_RESOURCE_KEY_NAME(rr->key));
245 else if (rr->key->type == DNS_TYPE_DNAME)
246 return dns_name_endswith(joined, DNS_RESOURCE_KEY_NAME(rr->key));
247 }
248
249 return 0;
250
74b2466e
LP
251}
252
b826ab58 253static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
322345fd 254 const DnsResourceKey *k = i;
322345fd 255
b826ab58 256 assert(k);
322345fd 257
b826ab58
TG
258 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state);
259 siphash24_compress(&k->class, sizeof(k->class), state);
260 siphash24_compress(&k->type, sizeof(k->type), state);
322345fd
LP
261}
262
d5099efc 263static int dns_resource_key_compare_func(const void *a, const void *b) {
322345fd
LP
264 const DnsResourceKey *x = a, *y = b;
265 int ret;
266
faa133f3 267 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
322345fd
LP
268 if (ret != 0)
269 return ret;
270
271 if (x->type < y->type)
272 return -1;
273 if (x->type > y->type)
274 return 1;
275
276 if (x->class < y->class)
277 return -1;
278 if (x->class > y->class)
279 return 1;
280
281 return 0;
282}
283
d5099efc
MS
284const struct hash_ops dns_resource_key_hash_ops = {
285 .hash = dns_resource_key_hash_func,
286 .compare = dns_resource_key_compare_func
287};
288
2d4c5cbc 289int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
d23a27a9 290 char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
2d4c5cbc
LP
291 const char *c, *t;
292 char *s;
293
294 c = dns_class_to_string(key->class);
295 if (!c) {
d23a27a9 296 sprintf(cbuf, "CLASS%u", key->class);
2d4c5cbc
LP
297 c = cbuf;
298 }
299
300 t = dns_type_to_string(key->type);
301 if (!t){
d23a27a9 302 sprintf(tbuf, "TYPE%u", key->type);
2d4c5cbc
LP
303 t = tbuf;
304 }
305
23432a1c 306 if (asprintf(&s, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key), c, t) < 0)
2d4c5cbc
LP
307 return -ENOMEM;
308
309 *ret = s;
310 return 0;
311}
312
faa133f3 313DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
74b2466e
LP
314 DnsResourceRecord *rr;
315
316 rr = new0(DnsResourceRecord, 1);
317 if (!rr)
318 return NULL;
319
320 rr->n_ref = 1;
faa133f3
LP
321 rr->key = dns_resource_key_ref(key);
322
74b2466e
LP
323 return rr;
324}
325
8bf52d3d
LP
326DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
327 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
328
329 key = dns_resource_key_new(class, type, name);
330 if (!key)
331 return NULL;
332
333 return dns_resource_record_new(key);
334}
335
74b2466e
LP
336DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
337 if (!rr)
338 return NULL;
339
340 assert(rr->n_ref > 0);
341 rr->n_ref++;
342
343 return rr;
344}
345
346DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
347 if (!rr)
348 return NULL;
349
350 assert(rr->n_ref > 0);
351
352 if (rr->n_ref > 1) {
353 rr->n_ref--;
354 return NULL;
355 }
356
faa133f3 357 if (rr->key) {
9de3e329 358 switch(rr->key->type) {
9c92ce6d
LP
359
360 case DNS_TYPE_SRV:
361 free(rr->srv.name);
362 break;
363
9de3e329
ZJS
364 case DNS_TYPE_PTR:
365 case DNS_TYPE_NS:
366 case DNS_TYPE_CNAME:
8ac4e9e1 367 case DNS_TYPE_DNAME:
faa133f3 368 free(rr->ptr.name);
9de3e329 369 break;
9c92ce6d 370
9de3e329 371 case DNS_TYPE_HINFO:
faa133f3
LP
372 free(rr->hinfo.cpu);
373 free(rr->hinfo.os);
9de3e329 374 break;
9c92ce6d 375
9de3e329 376 case DNS_TYPE_TXT:
9c92ce6d 377 case DNS_TYPE_SPF:
2001c805 378 dns_txt_item_free_all(rr->txt.items);
9de3e329 379 break;
9c92ce6d 380
9de3e329 381 case DNS_TYPE_SOA:
7e8e0422
LP
382 free(rr->soa.mname);
383 free(rr->soa.rname);
9de3e329 384 break;
9c92ce6d 385
9de3e329 386 case DNS_TYPE_MX:
946c7094 387 free(rr->mx.exchange);
9de3e329 388 break;
9c92ce6d 389
abf126a3
TG
390 case DNS_TYPE_DS:
391 free(rr->ds.digest);
392 break;
393
42cc2eeb 394 case DNS_TYPE_SSHFP:
549c1a25 395 free(rr->sshfp.fingerprint);
42cc2eeb
LP
396 break;
397
8db0d2f5
ZJS
398 case DNS_TYPE_DNSKEY:
399 free(rr->dnskey.key);
400 break;
401
151226ab
ZJS
402 case DNS_TYPE_RRSIG:
403 free(rr->rrsig.signer);
404 free(rr->rrsig.signature);
405 break;
406
50f1e641
TG
407 case DNS_TYPE_NSEC:
408 free(rr->nsec.next_domain_name);
409 bitmap_free(rr->nsec.types);
410 break;
411
5d45a880
TG
412 case DNS_TYPE_NSEC3:
413 free(rr->nsec3.next_hashed_name);
414 free(rr->nsec3.salt);
415 bitmap_free(rr->nsec3.types);
416 break;
417
0dae31d4 418 case DNS_TYPE_LOC:
9de3e329
ZJS
419 case DNS_TYPE_A:
420 case DNS_TYPE_AAAA:
421 break;
9c92ce6d 422
9de3e329 423 default:
faa133f3 424 free(rr->generic.data);
9de3e329 425 }
322345fd 426
a8812dd7 427 free(rr->wire_format);
faa133f3
LP
428 dns_resource_key_unref(rr->key);
429 }
322345fd 430
faa133f3 431 free(rr);
322345fd 432
322345fd
LP
433 return NULL;
434}
435
623a4c97
LP
436int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
437 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
438 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
439 _cleanup_free_ char *ptr = NULL;
440 int r;
441
442 assert(ret);
443 assert(address);
444 assert(hostname);
445
446 r = dns_name_reverse(family, address, &ptr);
447 if (r < 0)
448 return r;
449
450 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
451 if (!key)
452 return -ENOMEM;
453
454 ptr = NULL;
455
456 rr = dns_resource_record_new(key);
457 if (!rr)
458 return -ENOMEM;
459
460 rr->ptr.name = strdup(hostname);
461 if (!rr->ptr.name)
462 return -ENOMEM;
463
464 *ret = rr;
465 rr = NULL;
466
467 return 0;
468}
469
78c6a153
LP
470int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
471 DnsResourceRecord *rr;
472
473 assert(ret);
474 assert(address);
475 assert(family);
476
477 if (family == AF_INET) {
478
479 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
480 if (!rr)
481 return -ENOMEM;
482
483 rr->a.in_addr = address->in;
484
485 } else if (family == AF_INET6) {
486
487 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
488 if (!rr)
489 return -ENOMEM;
490
491 rr->aaaa.in6_addr = address->in6;
492 } else
493 return -EAFNOSUPPORT;
494
495 *ret = rr;
496
497 return 0;
498}
499
322345fd
LP
500int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
501 int r;
502
503 assert(a);
504 assert(b);
505
faa133f3 506 r = dns_resource_key_equal(a->key, b->key);
322345fd
LP
507 if (r <= 0)
508 return r;
509
fd0b4602
LP
510 if (a->unparseable != b->unparseable)
511 return 0;
512
513 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
2d4c5cbc 514
9c92ce6d
LP
515 case DNS_TYPE_SRV:
516 r = dns_name_equal(a->srv.name, b->srv.name);
517 if (r <= 0)
518 return r;
519
520 return a->srv.priority == b->srv.priority &&
521 a->srv.weight == b->srv.weight &&
522 a->srv.port == b->srv.port;
523
2d4c5cbc
LP
524 case DNS_TYPE_PTR:
525 case DNS_TYPE_NS:
526 case DNS_TYPE_CNAME:
8ac4e9e1 527 case DNS_TYPE_DNAME:
322345fd 528 return dns_name_equal(a->ptr.name, b->ptr.name);
2d4c5cbc
LP
529
530 case DNS_TYPE_HINFO:
531 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
532 strcaseeq(a->hinfo.os, b->hinfo.os);
533
9de3e329 534 case DNS_TYPE_SPF: /* exactly the same as TXT */
0f84a72e 535 case DNS_TYPE_TXT:
2001c805 536 return dns_txt_item_equal(a->txt.items, b->txt.items);
2e276efc 537
2d4c5cbc 538 case DNS_TYPE_A:
322345fd 539 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
2d4c5cbc
LP
540
541 case DNS_TYPE_AAAA:
322345fd 542 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
2d4c5cbc
LP
543
544 case DNS_TYPE_SOA:
7e8e0422
LP
545 r = dns_name_equal(a->soa.mname, b->soa.mname);
546 if (r <= 0)
547 return r;
548 r = dns_name_equal(a->soa.rname, b->soa.rname);
549 if (r <= 0)
550 return r;
551
552 return a->soa.serial == b->soa.serial &&
553 a->soa.refresh == b->soa.refresh &&
554 a->soa.retry == b->soa.retry &&
555 a->soa.expire == b->soa.expire &&
556 a->soa.minimum == b->soa.minimum;
9c92ce6d 557
946c7094
ZJS
558 case DNS_TYPE_MX:
559 if (a->mx.priority != b->mx.priority)
560 return 0;
561
562 return dns_name_equal(a->mx.exchange, b->mx.exchange);
563
0dae31d4
ZJS
564 case DNS_TYPE_LOC:
565 assert(a->loc.version == b->loc.version);
566
567 return a->loc.size == b->loc.size &&
568 a->loc.horiz_pre == b->loc.horiz_pre &&
569 a->loc.vert_pre == b->loc.vert_pre &&
570 a->loc.latitude == b->loc.latitude &&
571 a->loc.longitude == b->loc.longitude &&
572 a->loc.altitude == b->loc.altitude;
573
abf126a3
TG
574 case DNS_TYPE_DS:
575 return a->ds.key_tag == b->ds.key_tag &&
576 a->ds.algorithm == b->ds.algorithm &&
577 a->ds.digest_type == b->ds.digest_type &&
578 a->ds.digest_size == b->ds.digest_size &&
579 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
580
42cc2eeb
LP
581 case DNS_TYPE_SSHFP:
582 return a->sshfp.algorithm == b->sshfp.algorithm &&
583 a->sshfp.fptype == b->sshfp.fptype &&
549c1a25
TG
584 a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
585 memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
42cc2eeb 586
8db0d2f5 587 case DNS_TYPE_DNSKEY:
f91dc240
LP
588 return a->dnskey.flags == b->dnskey.flags &&
589 a->dnskey.protocol == b->dnskey.protocol &&
8db0d2f5
ZJS
590 a->dnskey.algorithm == b->dnskey.algorithm &&
591 a->dnskey.key_size == b->dnskey.key_size &&
592 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
593
151226ab
ZJS
594 case DNS_TYPE_RRSIG:
595 /* do the fast comparisons first */
03664a62
LN
596 if (a->rrsig.type_covered != b->rrsig.type_covered ||
597 a->rrsig.algorithm != b->rrsig.algorithm ||
598 a->rrsig.labels != b->rrsig.labels ||
599 a->rrsig.original_ttl != b->rrsig.original_ttl ||
600 a->rrsig.expiration != b->rrsig.expiration ||
601 a->rrsig.inception != b->rrsig.inception ||
602 a->rrsig.key_tag != b->rrsig.key_tag ||
151226ab
ZJS
603 a->rrsig.signature_size != b->rrsig.signature_size ||
604 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
605 return false;
606
607 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
608
50f1e641
TG
609 case DNS_TYPE_NSEC:
610 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
611 bitmap_equal(a->nsec.types, b->nsec.types);
612
5d45a880
TG
613 case DNS_TYPE_NSEC3:
614 return a->nsec3.algorithm == b->nsec3.algorithm &&
615 a->nsec3.flags == b->nsec3.flags &&
616 a->nsec3.iterations == b->nsec3.iterations &&
617 a->nsec3.salt_size == b->nsec3.salt_size &&
618 memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
619 memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
620 bitmap_equal(a->nsec3.types, b->nsec3.types);
621
2d4c5cbc 622 default:
322345fd
LP
623 return a->generic.size == b->generic.size &&
624 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
2d4c5cbc 625 }
322345fd
LP
626}
627
0dae31d4
ZJS
628static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
629 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
630 char *s;
631 char NS = latitude >= 1U<<31 ? 'N' : 'S';
632 char EW = longitude >= 1U<<31 ? 'E' : 'W';
633
634 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
635 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
636 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
637 double siz = (size >> 4) * exp10((double) (size & 0xF));
638 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
639 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
640
641 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
642 (lat / 60000 / 60),
643 (lat / 60000) % 60,
644 (lat % 60000) / 1000.,
645 NS,
646 (lon / 60000 / 60),
647 (lon / 60000) % 60,
648 (lon % 60000) / 1000.,
649 EW,
650 alt / 100.,
651 siz / 100.,
652 hor / 100.,
653 ver / 100.) < 0)
654 return NULL;
655
656 return s;
657}
658
7c6423e1
TG
659static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
660 struct tm tm;
661
662 assert(buf);
663 assert(l > strlen("YYYYMMDDHHmmSS"));
664
665 if (!gmtime_r(&sec, &tm))
666 return -EINVAL;
667
668 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
669 return -EINVAL;
670
671 return 0;
672}
673
50f1e641
TG
674static char *format_types(Bitmap *types) {
675 _cleanup_strv_free_ char **strv = NULL;
676 _cleanup_free_ char *str = NULL;
cb57dd41 677 Iterator i;
50f1e641
TG
678 unsigned type;
679 int r;
680
cb57dd41 681 BITMAP_FOREACH(type, types, i) {
50f1e641 682 if (dns_type_to_string(type)) {
2c1fb4f7 683 r = strv_extend(&strv, dns_type_to_string(type));
50f1e641
TG
684 if (r < 0)
685 return NULL;
686 } else {
687 char *t;
688
689 r = asprintf(&t, "TYPE%u", type);
690 if (r < 0)
691 return NULL;
692
2c1fb4f7 693 r = strv_consume(&strv, t);
50f1e641
TG
694 if (r < 0)
695 return NULL;
696 }
697 }
698
699 str = strv_join(strv, " ");
700 if (!str)
701 return NULL;
702
703 return strjoin("( ", str, " )", NULL);
704}
705
2001c805
LP
706static char *format_txt(DnsTxtItem *first) {
707 DnsTxtItem *i;
708 size_t c = 1;
709 char *p, *s;
710
711 LIST_FOREACH(items, i, first)
712 c += i->length * 4 + 3;
713
714 p = s = new(char, c);
715 if (!s)
716 return NULL;
717
718 LIST_FOREACH(items, i, first) {
719 size_t j;
720
721 if (i != first)
722 *(p++) = ' ';
723
724 *(p++) = '"';
725
726 for (j = 0; j < i->length; j++) {
727 if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) {
728 *(p++) = '\\';
729 *(p++) = '0' + (i->data[j] / 100);
730 *(p++) = '0' + ((i->data[j] / 10) % 10);
731 *(p++) = '0' + (i->data[j] % 10);
732 } else
733 *(p++) = i->data[j];
734 }
735
736 *(p++) = '"';
737 }
738
739 *p = 0;
740 return s;
741}
742
2d4c5cbc 743int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
8db0d2f5 744 _cleanup_free_ char *k = NULL, *t = NULL;
2d4c5cbc
LP
745 char *s;
746 int r;
322345fd 747
2d4c5cbc 748 assert(rr);
322345fd 749
2d4c5cbc
LP
750 r = dns_resource_key_to_string(rr->key, &k);
751 if (r < 0)
752 return r;
322345fd 753
0dae31d4 754 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
322345fd 755
9c92ce6d
LP
756 case DNS_TYPE_SRV:
757 r = asprintf(&s, "%s %u %u %u %s",
758 k,
759 rr->srv.priority,
760 rr->srv.weight,
761 rr->srv.port,
762 strna(rr->srv.name));
763 if (r < 0)
764 return -ENOMEM;
765 break;
766
2d4c5cbc
LP
767 case DNS_TYPE_PTR:
768 case DNS_TYPE_NS:
769 case DNS_TYPE_CNAME:
8ac4e9e1 770 case DNS_TYPE_DNAME:
2d4c5cbc
LP
771 s = strjoin(k, " ", rr->ptr.name, NULL);
772 if (!s)
773 return -ENOMEM;
322345fd 774
2d4c5cbc 775 break;
322345fd 776
2d4c5cbc
LP
777 case DNS_TYPE_HINFO:
778 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
779 if (!s)
780 return -ENOMEM;
781 break;
322345fd 782
9de3e329 783 case DNS_TYPE_SPF: /* exactly the same as TXT */
8db0d2f5 784 case DNS_TYPE_TXT:
2001c805 785 t = format_txt(rr->txt.items);
2e276efc
ZJS
786 if (!t)
787 return -ENOMEM;
788
789 s = strjoin(k, " ", t, NULL);
790 if (!s)
791 return -ENOMEM;
2e276efc 792 break;
2e276efc 793
2d4c5cbc
LP
794 case DNS_TYPE_A: {
795 _cleanup_free_ char *x = NULL;
322345fd 796
2d4c5cbc
LP
797 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
798 if (r < 0)
799 return r;
322345fd 800
2d4c5cbc
LP
801 s = strjoin(k, " ", x, NULL);
802 if (!s)
803 return -ENOMEM;
804 break;
805 }
322345fd 806
8db0d2f5
ZJS
807 case DNS_TYPE_AAAA:
808 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
2d4c5cbc
LP
809 if (r < 0)
810 return r;
322345fd 811
8db0d2f5 812 s = strjoin(k, " ", t, NULL);
2d4c5cbc
LP
813 if (!s)
814 return -ENOMEM;
815 break;
322345fd 816
2d4c5cbc
LP
817 case DNS_TYPE_SOA:
818 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
819 k,
820 strna(rr->soa.mname),
821 strna(rr->soa.rname),
822 rr->soa.serial,
823 rr->soa.refresh,
824 rr->soa.retry,
825 rr->soa.expire,
826 rr->soa.minimum);
827 if (r < 0)
828 return -ENOMEM;
829 break;
830
946c7094
ZJS
831 case DNS_TYPE_MX:
832 r = asprintf(&s, "%s %u %s",
833 k,
834 rr->mx.priority,
835 rr->mx.exchange);
836 if (r < 0)
837 return -ENOMEM;
838 break;
839
8db0d2f5 840 case DNS_TYPE_LOC:
0dae31d4
ZJS
841 assert(rr->loc.version == 0);
842
8db0d2f5
ZJS
843 t = format_location(rr->loc.latitude,
844 rr->loc.longitude,
845 rr->loc.altitude,
846 rr->loc.size,
847 rr->loc.horiz_pre,
848 rr->loc.vert_pre);
849 if (!t)
0dae31d4
ZJS
850 return -ENOMEM;
851
8db0d2f5 852 s = strjoin(k, " ", t, NULL);
0dae31d4
ZJS
853 if (!s)
854 return -ENOMEM;
0dae31d4 855 break;
0dae31d4 856
abf126a3
TG
857 case DNS_TYPE_DS:
858 t = hexmem(rr->ds.digest, rr->ds.digest_size);
859 if (!t)
860 return -ENOMEM;
861
862 r = asprintf(&s, "%s %u %u %u %s",
863 k,
864 rr->ds.key_tag,
865 rr->ds.algorithm,
866 rr->ds.digest_type,
867 t);
868 if (r < 0)
869 return -ENOMEM;
870 break;
871
8db0d2f5 872 case DNS_TYPE_SSHFP:
549c1a25 873 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
8db0d2f5 874 if (!t)
42cc2eeb
LP
875 return -ENOMEM;
876
877 r = asprintf(&s, "%s %u %u %s",
878 k,
879 rr->sshfp.algorithm,
880 rr->sshfp.fptype,
8db0d2f5 881 t);
42cc2eeb
LP
882 if (r < 0)
883 return -ENOMEM;
884 break;
42cc2eeb 885
ff3d6560
ZJS
886 case DNS_TYPE_DNSKEY: {
887 const char *alg;
888
889 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
890
1bf968f3 891 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
8db0d2f5
ZJS
892 if (!t)
893 return -ENOMEM;
2d4c5cbc 894
f91dc240 895 r = asprintf(&s, "%s %u %u %.*s%.*u %s",
8db0d2f5 896 k,
f91dc240
LP
897 rr->dnskey.flags,
898 rr->dnskey.protocol,
ff3d6560
ZJS
899 alg ? -1 : 0, alg,
900 alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
8db0d2f5
ZJS
901 t);
902 if (r < 0)
2d4c5cbc 903 return -ENOMEM;
8db0d2f5 904 break;
ff3d6560 905 }
2d4c5cbc 906
151226ab
ZJS
907 case DNS_TYPE_RRSIG: {
908 const char *type, *alg;
7c6423e1 909 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
151226ab
ZJS
910
911 type = dns_type_to_string(rr->rrsig.type_covered);
912 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
913
1bf968f3 914 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
151226ab
ZJS
915 if (!t)
916 return -ENOMEM;
917
7c6423e1
TG
918 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
919 if (r < 0)
920 return r;
921
922 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
923 if (r < 0)
924 return r;
925
151226ab
ZJS
926 /* TYPE?? follows
927 * http://tools.ietf.org/html/rfc3597#section-5 */
928
7c6423e1 929 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
151226ab
ZJS
930 k,
931 type ?: "TYPE",
932 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
933 alg ? -1 : 0, alg,
934 alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
935 rr->rrsig.labels,
936 rr->rrsig.original_ttl,
7c6423e1
TG
937 expiration,
938 inception,
151226ab
ZJS
939 rr->rrsig.key_tag,
940 rr->rrsig.signer,
941 t);
942 if (r < 0)
943 return -ENOMEM;
944 break;
945 }
946
50f1e641
TG
947 case DNS_TYPE_NSEC:
948 t = format_types(rr->nsec.types);
949 if (!t)
950 return -ENOMEM;
951
952 r = asprintf(&s, "%s %s %s",
953 k,
954 rr->nsec.next_domain_name,
955 t);
956 if (r < 0)
957 return -ENOMEM;
958 break;
959
5d45a880
TG
960 case DNS_TYPE_NSEC3: {
961 _cleanup_free_ char *salt = NULL, *hash = NULL;
962
f5430a3e 963 if (rr->nsec3.salt_size > 0) {
5d45a880
TG
964 salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
965 if (!salt)
966 return -ENOMEM;
967 }
968
969 hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
970 if (!hash)
971 return -ENOMEM;
972
973 t = format_types(rr->nsec3.types);
974 if (!t)
975 return -ENOMEM;
976
977 r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
978 k,
979 rr->nsec3.algorithm,
980 rr->nsec3.flags,
981 rr->nsec3.iterations,
f5430a3e 982 rr->nsec3.salt_size > 0 ? salt : "-",
5d45a880
TG
983 hash,
984 t);
985 if (r < 0)
986 return -ENOMEM;
987
988 break;
989 }
990
8db0d2f5
ZJS
991 default:
992 t = hexmem(rr->generic.data, rr->generic.size);
993 if (!t)
994 return -ENOMEM;
995
f5430a3e 996 r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
d23a27a9 997 if (r < 0)
2d4c5cbc
LP
998 return -ENOMEM;
999 break;
8db0d2f5 1000 }
2d4c5cbc
LP
1001
1002 *ret = s;
1003 return 0;
1004}
322345fd 1005
a8812dd7
LP
1006int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {
1007
1008 DnsPacket packet = {
1009 .n_ref = 1,
1010 .protocol = DNS_PROTOCOL_DNS,
1011 .on_stack = true,
1012 .refuse_compression = true,
1013 .canonical_form = canonical,
1014 };
1015
1016 size_t start, rds;
1017 int r;
1018
1019 assert(rr);
1020
1021 /* Generates the RR in wire-format, optionally in the
1022 * canonical form as discussed in the DNSSEC RFC 4034, Section
1023 * 6.2. We allocate a throw-away DnsPacket object on the stack
1024 * here, because we need some book-keeping for memory
1025 * management, and can reuse the DnsPacket serializer, that
1026 * can generate the canonical form, too, but also knows label
1027 * compression and suchlike. */
1028
1029 if (rr->wire_format && rr->wire_format_canonical == canonical)
1030 return 0;
1031
1032 r = dns_packet_append_rr(&packet, rr, &start, &rds);
1033 if (r < 0)
1034 return r;
1035
1036 assert(start == 0);
1037 assert(packet._data);
1038
1039 free(rr->wire_format);
1040 rr->wire_format = packet._data;
1041 rr->wire_format_size = packet.size;
1042 rr->wire_format_rdata_offset = rds;
1043 rr->wire_format_canonical = canonical;
1044
1045 packet._data = NULL;
1046 dns_packet_unref(&packet);
1047
1048 return 0;
1049}
1050
2d4c5cbc 1051const char *dns_class_to_string(uint16_t class) {
322345fd 1052
2d4c5cbc 1053 switch (class) {
322345fd 1054
2d4c5cbc
LP
1055 case DNS_CLASS_IN:
1056 return "IN";
322345fd 1057
2d4c5cbc
LP
1058 case DNS_CLASS_ANY:
1059 return "ANY";
1060 }
322345fd 1061
2d4c5cbc
LP
1062 return NULL;
1063}
322345fd 1064
2d4c5cbc
LP
1065int dns_class_from_string(const char *s, uint16_t *class) {
1066 assert(s);
1067 assert(class);
1068
1069 if (strcaseeq(s, "IN"))
1070 *class = DNS_CLASS_IN;
1071 else if (strcaseeq(s, "ANY"))
816b4547 1072 *class = DNS_CLASS_ANY;
2d4c5cbc
LP
1073 else
1074 return -EINVAL;
322345fd 1075
2d4c5cbc
LP
1076 return 0;
1077}
2001c805
LP
1078
1079DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
1080 DnsTxtItem *n;
1081
1082 if (!i)
1083 return NULL;
1084
1085 n = i->items_next;
1086
1087 free(i);
1088 return dns_txt_item_free_all(n);
1089}
1090
1091bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
1092
1093 if (!a != !b)
1094 return false;
1095
1096 if (!a)
1097 return true;
1098
1099 if (a->length != b->length)
1100 return false;
1101
1102 if (memcmp(a->data, b->data, a->length) != 0)
1103 return false;
1104
1105 return dns_txt_item_equal(a->items_next, b->items_next);
1106}
8730bccf
LP
1107
1108static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
1109 [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
1110 [DNSSEC_ALGORITHM_DH] = "DH",
1111 [DNSSEC_ALGORITHM_DSA] = "DSA",
1112 [DNSSEC_ALGORITHM_ECC] = "ECC",
1113 [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
1114 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1",
1115 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1",
1116 [DNSSEC_ALGORITHM_RSASHA256] = "RSASHA256",
1117 [DNSSEC_ALGORITHM_RSASHA512] = "RSASHA512",
1118 [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
1119 [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
1120 [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
1121};
1122DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int);
1123
1124static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = {
1125 [DNSSEC_DIGEST_SHA1] = "SHA1",
1126 [DNSSEC_DIGEST_SHA256] = "SHA256",
1127};
1128DEFINE_STRING_TABLE_LOOKUP(dnssec_digest, int);