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