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