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