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