]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-rr.c
resolved: when switching between DNSSEC modes, possibly flush caches
[thirdparty/systemd.git] / src / resolve / resolved-dns-rr.c
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
22 #include <math.h>
23
24 #include "alloc-util.h"
25 #include "dns-domain.h"
26 #include "dns-type.h"
27 #include "hexdecoct.h"
28 #include "resolved-dns-packet.h"
29 #include "resolved-dns-rr.h"
30 #include "string-table.h"
31 #include "string-util.h"
32 #include "strv.h"
33
34 DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
35 DnsResourceKey *k;
36 size_t l;
37
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
54 DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) {
55 int r;
56
57 assert(key);
58 assert(cname);
59
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 }
82 }
83
84 int 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
93 if (dns_name_is_root(name)) {
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
112 DnsResourceKey* 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
129 DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
130
131 if (!k)
132 return NULL;
133
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
138 assert(k->n_ref > 0);
139 k->n_ref++;
140
141 return k;
142 }
143
144 DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
145 if (!k)
146 return NULL;
147
148 assert(k->n_ref != (unsigned) -1);
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
160 bool 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
168 int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
169 int r;
170
171 if (a == b)
172 return 1;
173
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
187 int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, const char *search_domain) {
188 int r;
189
190 assert(key);
191 assert(rr);
192
193 if (key == rr->key)
194 return 1;
195
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
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
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;
221 }
222
223 int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain) {
224 int r;
225
226 assert(key);
227 assert(cname);
228
229 if (cname->class != key->class && key->class != DNS_CLASS_ANY)
230 return 0;
231
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));
236 else
237 return 0;
238
239 if (r != 0)
240 return r;
241
242 if (search_domain) {
243 _cleanup_free_ char *joined = NULL;
244
245 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
246 if (r < 0)
247 return r;
248
249 if (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));
253 }
254
255 return 0;
256 }
257
258 int 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
264 if (soa->class != key->class)
265 return 0;
266
267 if (soa->type != DNS_TYPE_SOA)
268 return 0;
269
270 return dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(soa));
271 }
272
273 static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
274 const DnsResourceKey *k = i;
275
276 assert(k);
277
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);
281 }
282
283 static int dns_resource_key_compare_func(const void *a, const void *b) {
284 const DnsResourceKey *x = a, *y = b;
285 int ret;
286
287 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
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
304 const struct hash_ops dns_resource_key_hash_ops = {
305 .hash = dns_resource_key_hash_func,
306 .compare = dns_resource_key_compare_func
307 };
308
309 int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
310 char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
311 const char *c, *t, *n;
312 char *s;
313
314 /* If we cannot convert the CLASS/TYPE into a known string,
315 use the format recommended by RFC 3597, Section 5. */
316
317 c = dns_class_to_string(key->class);
318 if (!c) {
319 sprintf(cbuf, "CLASS%u", key->class);
320 c = cbuf;
321 }
322
323 t = dns_type_to_string(key->type);
324 if (!t){
325 sprintf(tbuf, "TYPE%u", key->type);
326 t = tbuf;
327 }
328
329 n = DNS_RESOURCE_KEY_NAME(key);
330 if (asprintf(&s, "%s%s %s %-5s", n, endswith(n, ".") ? "" : ".", c, t) < 0)
331 return -ENOMEM;
332
333 *ret = s;
334 return 0;
335 }
336
337 DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
338 DnsResourceRecord *rr;
339
340 rr = new0(DnsResourceRecord, 1);
341 if (!rr)
342 return NULL;
343
344 rr->n_ref = 1;
345 rr->key = dns_resource_key_ref(key);
346 rr->expiry = USEC_INFINITY;
347 rr->n_skip_labels_signer = rr->n_skip_labels_source = (unsigned) -1;
348
349 return rr;
350 }
351
352 DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
353 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
354
355 key = dns_resource_key_new(class, type, name);
356 if (!key)
357 return NULL;
358
359 return dns_resource_record_new(key);
360 }
361
362 DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
363 if (!rr)
364 return NULL;
365
366 assert(rr->n_ref > 0);
367 rr->n_ref++;
368
369 return rr;
370 }
371
372 DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
373 if (!rr)
374 return NULL;
375
376 assert(rr->n_ref > 0);
377
378 if (rr->n_ref > 1) {
379 rr->n_ref--;
380 return NULL;
381 }
382
383 if (rr->key) {
384 switch(rr->key->type) {
385
386 case DNS_TYPE_SRV:
387 free(rr->srv.name);
388 break;
389
390 case DNS_TYPE_PTR:
391 case DNS_TYPE_NS:
392 case DNS_TYPE_CNAME:
393 case DNS_TYPE_DNAME:
394 free(rr->ptr.name);
395 break;
396
397 case DNS_TYPE_HINFO:
398 free(rr->hinfo.cpu);
399 free(rr->hinfo.os);
400 break;
401
402 case DNS_TYPE_TXT:
403 case DNS_TYPE_SPF:
404 dns_txt_item_free_all(rr->txt.items);
405 break;
406
407 case DNS_TYPE_SOA:
408 free(rr->soa.mname);
409 free(rr->soa.rname);
410 break;
411
412 case DNS_TYPE_MX:
413 free(rr->mx.exchange);
414 break;
415
416 case DNS_TYPE_DS:
417 free(rr->ds.digest);
418 break;
419
420 case DNS_TYPE_SSHFP:
421 free(rr->sshfp.fingerprint);
422 break;
423
424 case DNS_TYPE_DNSKEY:
425 free(rr->dnskey.key);
426 break;
427
428 case DNS_TYPE_RRSIG:
429 free(rr->rrsig.signer);
430 free(rr->rrsig.signature);
431 break;
432
433 case DNS_TYPE_NSEC:
434 free(rr->nsec.next_domain_name);
435 bitmap_free(rr->nsec.types);
436 break;
437
438 case DNS_TYPE_NSEC3:
439 free(rr->nsec3.next_hashed_name);
440 free(rr->nsec3.salt);
441 bitmap_free(rr->nsec3.types);
442 break;
443
444 case DNS_TYPE_LOC:
445 case DNS_TYPE_A:
446 case DNS_TYPE_AAAA:
447 break;
448
449 default:
450 free(rr->generic.data);
451 }
452
453 free(rr->wire_format);
454 dns_resource_key_unref(rr->key);
455 }
456
457 free(rr->to_string);
458 free(rr);
459
460 return NULL;
461 }
462
463 int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
464 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
465 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
466 _cleanup_free_ char *ptr = NULL;
467 int r;
468
469 assert(ret);
470 assert(address);
471 assert(hostname);
472
473 r = dns_name_reverse(family, address, &ptr);
474 if (r < 0)
475 return r;
476
477 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
478 if (!key)
479 return -ENOMEM;
480
481 ptr = NULL;
482
483 rr = dns_resource_record_new(key);
484 if (!rr)
485 return -ENOMEM;
486
487 rr->ptr.name = strdup(hostname);
488 if (!rr->ptr.name)
489 return -ENOMEM;
490
491 *ret = rr;
492 rr = NULL;
493
494 return 0;
495 }
496
497 int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
498 DnsResourceRecord *rr;
499
500 assert(ret);
501 assert(address);
502 assert(family);
503
504 if (family == AF_INET) {
505
506 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
507 if (!rr)
508 return -ENOMEM;
509
510 rr->a.in_addr = address->in;
511
512 } else if (family == AF_INET6) {
513
514 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
515 if (!rr)
516 return -ENOMEM;
517
518 rr->aaaa.in6_addr = address->in6;
519 } else
520 return -EAFNOSUPPORT;
521
522 *ret = rr;
523
524 return 0;
525 }
526
527 int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
528 int r;
529
530 assert(a);
531 assert(b);
532
533 if (a == b)
534 return 1;
535
536 r = dns_resource_key_equal(a->key, b->key);
537 if (r <= 0)
538 return r;
539
540 if (a->unparseable != b->unparseable)
541 return 0;
542
543 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
544
545 case DNS_TYPE_SRV:
546 r = dns_name_equal(a->srv.name, b->srv.name);
547 if (r <= 0)
548 return r;
549
550 return a->srv.priority == b->srv.priority &&
551 a->srv.weight == b->srv.weight &&
552 a->srv.port == b->srv.port;
553
554 case DNS_TYPE_PTR:
555 case DNS_TYPE_NS:
556 case DNS_TYPE_CNAME:
557 case DNS_TYPE_DNAME:
558 return dns_name_equal(a->ptr.name, b->ptr.name);
559
560 case DNS_TYPE_HINFO:
561 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
562 strcaseeq(a->hinfo.os, b->hinfo.os);
563
564 case DNS_TYPE_SPF: /* exactly the same as TXT */
565 case DNS_TYPE_TXT:
566 return dns_txt_item_equal(a->txt.items, b->txt.items);
567
568 case DNS_TYPE_A:
569 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
570
571 case DNS_TYPE_AAAA:
572 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
573
574 case DNS_TYPE_SOA:
575 r = dns_name_equal(a->soa.mname, b->soa.mname);
576 if (r <= 0)
577 return r;
578 r = dns_name_equal(a->soa.rname, b->soa.rname);
579 if (r <= 0)
580 return r;
581
582 return a->soa.serial == b->soa.serial &&
583 a->soa.refresh == b->soa.refresh &&
584 a->soa.retry == b->soa.retry &&
585 a->soa.expire == b->soa.expire &&
586 a->soa.minimum == b->soa.minimum;
587
588 case DNS_TYPE_MX:
589 if (a->mx.priority != b->mx.priority)
590 return 0;
591
592 return dns_name_equal(a->mx.exchange, b->mx.exchange);
593
594 case DNS_TYPE_LOC:
595 assert(a->loc.version == b->loc.version);
596
597 return a->loc.size == b->loc.size &&
598 a->loc.horiz_pre == b->loc.horiz_pre &&
599 a->loc.vert_pre == b->loc.vert_pre &&
600 a->loc.latitude == b->loc.latitude &&
601 a->loc.longitude == b->loc.longitude &&
602 a->loc.altitude == b->loc.altitude;
603
604 case DNS_TYPE_DS:
605 return a->ds.key_tag == b->ds.key_tag &&
606 a->ds.algorithm == b->ds.algorithm &&
607 a->ds.digest_type == b->ds.digest_type &&
608 a->ds.digest_size == b->ds.digest_size &&
609 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
610
611 case DNS_TYPE_SSHFP:
612 return a->sshfp.algorithm == b->sshfp.algorithm &&
613 a->sshfp.fptype == b->sshfp.fptype &&
614 a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
615 memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
616
617 case DNS_TYPE_DNSKEY:
618 return a->dnskey.flags == b->dnskey.flags &&
619 a->dnskey.protocol == b->dnskey.protocol &&
620 a->dnskey.algorithm == b->dnskey.algorithm &&
621 a->dnskey.key_size == b->dnskey.key_size &&
622 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
623
624 case DNS_TYPE_RRSIG:
625 /* do the fast comparisons first */
626 if (a->rrsig.type_covered != b->rrsig.type_covered ||
627 a->rrsig.algorithm != b->rrsig.algorithm ||
628 a->rrsig.labels != b->rrsig.labels ||
629 a->rrsig.original_ttl != b->rrsig.original_ttl ||
630 a->rrsig.expiration != b->rrsig.expiration ||
631 a->rrsig.inception != b->rrsig.inception ||
632 a->rrsig.key_tag != b->rrsig.key_tag ||
633 a->rrsig.signature_size != b->rrsig.signature_size ||
634 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
635 return false;
636
637 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
638
639 case DNS_TYPE_NSEC:
640 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
641 bitmap_equal(a->nsec.types, b->nsec.types);
642
643 case DNS_TYPE_NSEC3:
644 return a->nsec3.algorithm == b->nsec3.algorithm &&
645 a->nsec3.flags == b->nsec3.flags &&
646 a->nsec3.iterations == b->nsec3.iterations &&
647 a->nsec3.salt_size == b->nsec3.salt_size &&
648 memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
649 memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
650 bitmap_equal(a->nsec3.types, b->nsec3.types);
651
652 default:
653 return a->generic.size == b->generic.size &&
654 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
655 }
656 }
657
658 static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
659 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
660 char *s;
661 char NS = latitude >= 1U<<31 ? 'N' : 'S';
662 char EW = longitude >= 1U<<31 ? 'E' : 'W';
663
664 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
665 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
666 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
667 double siz = (size >> 4) * exp10((double) (size & 0xF));
668 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
669 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
670
671 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
672 (lat / 60000 / 60),
673 (lat / 60000) % 60,
674 (lat % 60000) / 1000.,
675 NS,
676 (lon / 60000 / 60),
677 (lon / 60000) % 60,
678 (lon % 60000) / 1000.,
679 EW,
680 alt / 100.,
681 siz / 100.,
682 hor / 100.,
683 ver / 100.) < 0)
684 return NULL;
685
686 return s;
687 }
688
689 static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
690 struct tm tm;
691
692 assert(buf);
693 assert(l > strlen("YYYYMMDDHHmmSS"));
694
695 if (!gmtime_r(&sec, &tm))
696 return -EINVAL;
697
698 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
699 return -EINVAL;
700
701 return 0;
702 }
703
704 static char *format_types(Bitmap *types) {
705 _cleanup_strv_free_ char **strv = NULL;
706 _cleanup_free_ char *str = NULL;
707 Iterator i;
708 unsigned type;
709 int r;
710
711 BITMAP_FOREACH(type, types, i) {
712 if (dns_type_to_string(type)) {
713 r = strv_extend(&strv, dns_type_to_string(type));
714 if (r < 0)
715 return NULL;
716 } else {
717 char *t;
718
719 r = asprintf(&t, "TYPE%u", type);
720 if (r < 0)
721 return NULL;
722
723 r = strv_consume(&strv, t);
724 if (r < 0)
725 return NULL;
726 }
727 }
728
729 str = strv_join(strv, " ");
730 if (!str)
731 return NULL;
732
733 return strjoin("( ", str, " )", NULL);
734 }
735
736 static char *format_txt(DnsTxtItem *first) {
737 DnsTxtItem *i;
738 size_t c = 1;
739 char *p, *s;
740
741 LIST_FOREACH(items, i, first)
742 c += i->length * 4 + 3;
743
744 p = s = new(char, c);
745 if (!s)
746 return NULL;
747
748 LIST_FOREACH(items, i, first) {
749 size_t j;
750
751 if (i != first)
752 *(p++) = ' ';
753
754 *(p++) = '"';
755
756 for (j = 0; j < i->length; j++) {
757 if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) {
758 *(p++) = '\\';
759 *(p++) = '0' + (i->data[j] / 100);
760 *(p++) = '0' + ((i->data[j] / 10) % 10);
761 *(p++) = '0' + (i->data[j] % 10);
762 } else
763 *(p++) = i->data[j];
764 }
765
766 *(p++) = '"';
767 }
768
769 *p = 0;
770 return s;
771 }
772
773 const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
774 _cleanup_free_ char *k = NULL, *t = NULL;
775 char *s;
776 int r;
777
778 assert(rr);
779
780 if (rr->to_string)
781 return rr->to_string;
782
783 r = dns_resource_key_to_string(rr->key, &k);
784 if (r < 0)
785 return NULL;
786
787 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
788
789 case DNS_TYPE_SRV:
790 r = asprintf(&s, "%s %u %u %u %s",
791 k,
792 rr->srv.priority,
793 rr->srv.weight,
794 rr->srv.port,
795 strna(rr->srv.name));
796 if (r < 0)
797 return NULL;
798 break;
799
800 case DNS_TYPE_PTR:
801 case DNS_TYPE_NS:
802 case DNS_TYPE_CNAME:
803 case DNS_TYPE_DNAME:
804 s = strjoin(k, " ", rr->ptr.name, NULL);
805 if (!s)
806 return NULL;
807
808 break;
809
810 case DNS_TYPE_HINFO:
811 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
812 if (!s)
813 return NULL;
814 break;
815
816 case DNS_TYPE_SPF: /* exactly the same as TXT */
817 case DNS_TYPE_TXT:
818 t = format_txt(rr->txt.items);
819 if (!t)
820 return NULL;
821
822 s = strjoin(k, " ", t, NULL);
823 if (!s)
824 return NULL;
825 break;
826
827 case DNS_TYPE_A: {
828 _cleanup_free_ char *x = NULL;
829
830 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
831 if (r < 0)
832 return NULL;
833
834 s = strjoin(k, " ", x, NULL);
835 if (!s)
836 return NULL;
837 break;
838 }
839
840 case DNS_TYPE_AAAA:
841 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
842 if (r < 0)
843 return NULL;
844
845 s = strjoin(k, " ", t, NULL);
846 if (!s)
847 return NULL;
848 break;
849
850 case DNS_TYPE_SOA:
851 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
852 k,
853 strna(rr->soa.mname),
854 strna(rr->soa.rname),
855 rr->soa.serial,
856 rr->soa.refresh,
857 rr->soa.retry,
858 rr->soa.expire,
859 rr->soa.minimum);
860 if (r < 0)
861 return NULL;
862 break;
863
864 case DNS_TYPE_MX:
865 r = asprintf(&s, "%s %u %s",
866 k,
867 rr->mx.priority,
868 rr->mx.exchange);
869 if (r < 0)
870 return NULL;
871 break;
872
873 case DNS_TYPE_LOC:
874 assert(rr->loc.version == 0);
875
876 t = format_location(rr->loc.latitude,
877 rr->loc.longitude,
878 rr->loc.altitude,
879 rr->loc.size,
880 rr->loc.horiz_pre,
881 rr->loc.vert_pre);
882 if (!t)
883 return NULL;
884
885 s = strjoin(k, " ", t, NULL);
886 if (!s)
887 return NULL;
888 break;
889
890 case DNS_TYPE_DS:
891 t = hexmem(rr->ds.digest, rr->ds.digest_size);
892 if (!t)
893 return NULL;
894
895 r = asprintf(&s, "%s %u %u %u %s",
896 k,
897 rr->ds.key_tag,
898 rr->ds.algorithm,
899 rr->ds.digest_type,
900 t);
901 if (r < 0)
902 return NULL;
903 break;
904
905 case DNS_TYPE_SSHFP:
906 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
907 if (!t)
908 return NULL;
909
910 r = asprintf(&s, "%s %u %u %s",
911 k,
912 rr->sshfp.algorithm,
913 rr->sshfp.fptype,
914 t);
915 if (r < 0)
916 return NULL;
917 break;
918
919 case DNS_TYPE_DNSKEY: {
920 _cleanup_free_ char *alg = NULL;
921
922 r = dnssec_algorithm_to_string_alloc(rr->dnskey.algorithm, &alg);
923 if (r < 0)
924 return NULL;
925
926 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
927 if (!t)
928 return NULL;
929
930 r = asprintf(&s, "%s %u %u %s %s",
931 k,
932 rr->dnskey.flags,
933 rr->dnskey.protocol,
934 alg,
935 t);
936 if (r < 0)
937 return NULL;
938 break;
939 }
940
941 case DNS_TYPE_RRSIG: {
942 _cleanup_free_ char *alg = NULL;
943 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
944 const char *type;
945
946 type = dns_type_to_string(rr->rrsig.type_covered);
947
948 r = dnssec_algorithm_to_string_alloc(rr->rrsig.algorithm, &alg);
949 if (r < 0)
950 return NULL;
951
952 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
953 if (!t)
954 return NULL;
955
956 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
957 if (r < 0)
958 return NULL;
959
960 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
961 if (r < 0)
962 return NULL;
963
964 /* TYPE?? follows
965 * http://tools.ietf.org/html/rfc3597#section-5 */
966
967 r = asprintf(&s, "%s %s%.*u %s %u %u %s %s %u %s %s",
968 k,
969 type ?: "TYPE",
970 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
971 alg,
972 rr->rrsig.labels,
973 rr->rrsig.original_ttl,
974 expiration,
975 inception,
976 rr->rrsig.key_tag,
977 rr->rrsig.signer,
978 t);
979 if (r < 0)
980 return NULL;
981 break;
982 }
983
984 case DNS_TYPE_NSEC:
985 t = format_types(rr->nsec.types);
986 if (!t)
987 return NULL;
988
989 r = asprintf(&s, "%s %s %s",
990 k,
991 rr->nsec.next_domain_name,
992 t);
993 if (r < 0)
994 return NULL;
995 break;
996
997 case DNS_TYPE_NSEC3: {
998 _cleanup_free_ char *salt = NULL, *hash = NULL;
999
1000 if (rr->nsec3.salt_size > 0) {
1001 salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
1002 if (!salt)
1003 return NULL;
1004 }
1005
1006 hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
1007 if (!hash)
1008 return NULL;
1009
1010 t = format_types(rr->nsec3.types);
1011 if (!t)
1012 return NULL;
1013
1014 r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
1015 k,
1016 rr->nsec3.algorithm,
1017 rr->nsec3.flags,
1018 rr->nsec3.iterations,
1019 rr->nsec3.salt_size > 0 ? salt : "-",
1020 hash,
1021 t);
1022 if (r < 0)
1023 return NULL;
1024
1025 break;
1026 }
1027
1028 default:
1029 t = hexmem(rr->generic.data, rr->generic.size);
1030 if (!t)
1031 return NULL;
1032
1033 /* Format as documented in RFC 3597, Section 5 */
1034 r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
1035 if (r < 0)
1036 return NULL;
1037 break;
1038 }
1039
1040 rr->to_string = s;
1041 return s;
1042 }
1043
1044 int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {
1045
1046 DnsPacket packet = {
1047 .n_ref = 1,
1048 .protocol = DNS_PROTOCOL_DNS,
1049 .on_stack = true,
1050 .refuse_compression = true,
1051 .canonical_form = canonical,
1052 };
1053
1054 size_t start, rds;
1055 int r;
1056
1057 assert(rr);
1058
1059 /* Generates the RR in wire-format, optionally in the
1060 * canonical form as discussed in the DNSSEC RFC 4034, Section
1061 * 6.2. We allocate a throw-away DnsPacket object on the stack
1062 * here, because we need some book-keeping for memory
1063 * management, and can reuse the DnsPacket serializer, that
1064 * can generate the canonical form, too, but also knows label
1065 * compression and suchlike. */
1066
1067 if (rr->wire_format && rr->wire_format_canonical == canonical)
1068 return 0;
1069
1070 r = dns_packet_append_rr(&packet, rr, &start, &rds);
1071 if (r < 0)
1072 return r;
1073
1074 assert(start == 0);
1075 assert(packet._data);
1076
1077 free(rr->wire_format);
1078 rr->wire_format = packet._data;
1079 rr->wire_format_size = packet.size;
1080 rr->wire_format_rdata_offset = rds;
1081 rr->wire_format_canonical = canonical;
1082
1083 packet._data = NULL;
1084 dns_packet_unref(&packet);
1085
1086 return 0;
1087 }
1088
1089 int dns_resource_record_signer(DnsResourceRecord *rr, const char **ret) {
1090 const char *n;
1091 int r;
1092
1093 assert(rr);
1094 assert(ret);
1095
1096 /* Returns the RRset's signer, if it is known. */
1097
1098 if (rr->n_skip_labels_signer == (unsigned) -1)
1099 return -ENODATA;
1100
1101 n = DNS_RESOURCE_KEY_NAME(rr->key);
1102 r = dns_name_skip(n, rr->n_skip_labels_signer, &n);
1103 if (r < 0)
1104 return r;
1105 if (r == 0)
1106 return -EINVAL;
1107
1108 *ret = n;
1109 return 0;
1110 }
1111
1112 int dns_resource_record_source(DnsResourceRecord *rr, const char **ret) {
1113 const char *n;
1114 int r;
1115
1116 assert(rr);
1117 assert(ret);
1118
1119 /* Returns the RRset's synthesizing source, if it is known. */
1120
1121 if (rr->n_skip_labels_source == (unsigned) -1)
1122 return -ENODATA;
1123
1124 n = DNS_RESOURCE_KEY_NAME(rr->key);
1125 r = dns_name_skip(n, rr->n_skip_labels_source, &n);
1126 if (r < 0)
1127 return r;
1128 if (r == 0)
1129 return -EINVAL;
1130
1131 *ret = n;
1132 return 0;
1133 }
1134
1135 int dns_resource_record_is_signer(DnsResourceRecord *rr, const char *zone) {
1136 const char *signer;
1137 int r;
1138
1139 assert(rr);
1140
1141 r = dns_resource_record_signer(rr, &signer);
1142 if (r < 0)
1143 return r;
1144
1145 return dns_name_equal(zone, signer);
1146 }
1147
1148 int dns_resource_record_is_synthetic(DnsResourceRecord *rr) {
1149 int r;
1150
1151 assert(rr);
1152
1153 /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */
1154
1155 if (rr->n_skip_labels_source == (unsigned) -1)
1156 return -ENODATA;
1157
1158 if (rr->n_skip_labels_source == 0)
1159 return 0;
1160
1161 if (rr->n_skip_labels_source > 1)
1162 return 1;
1163
1164 r = dns_name_startswith(DNS_RESOURCE_KEY_NAME(rr->key), "*");
1165 if (r < 0)
1166 return r;
1167
1168 return !r;
1169 }
1170
1171 static void dns_resource_record_hash_func(const void *i, struct siphash *state) {
1172 const DnsResourceRecord *rr = i;
1173
1174 assert(rr);
1175
1176 dns_resource_key_hash_func(rr->key, state);
1177
1178 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
1179
1180 case DNS_TYPE_SRV:
1181 siphash24_compress(&rr->srv.priority, sizeof(rr->srv.priority), state);
1182 siphash24_compress(&rr->srv.weight, sizeof(rr->srv.weight), state);
1183 siphash24_compress(&rr->srv.port, sizeof(rr->srv.port), state);
1184 dns_name_hash_func(rr->srv.name, state);
1185 break;
1186
1187 case DNS_TYPE_PTR:
1188 case DNS_TYPE_NS:
1189 case DNS_TYPE_CNAME:
1190 case DNS_TYPE_DNAME:
1191 dns_name_hash_func(rr->ptr.name, state);
1192 break;
1193
1194 case DNS_TYPE_HINFO:
1195 string_hash_func(rr->hinfo.cpu, state);
1196 string_hash_func(rr->hinfo.os, state);
1197 break;
1198
1199 case DNS_TYPE_TXT:
1200 case DNS_TYPE_SPF: {
1201 DnsTxtItem *j;
1202
1203 LIST_FOREACH(items, j, rr->txt.items) {
1204 siphash24_compress(j->data, j->length, state);
1205
1206 /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab"
1207 * followed by "". */
1208 siphash24_compress_byte(0, state);
1209 }
1210 break;
1211 }
1212
1213 case DNS_TYPE_A:
1214 siphash24_compress(&rr->a.in_addr, sizeof(rr->a.in_addr), state);
1215 break;
1216
1217 case DNS_TYPE_AAAA:
1218 siphash24_compress(&rr->aaaa.in6_addr, sizeof(rr->aaaa.in6_addr), state);
1219 break;
1220
1221 case DNS_TYPE_SOA:
1222 dns_name_hash_func(rr->soa.mname, state);
1223 dns_name_hash_func(rr->soa.rname, state);
1224 siphash24_compress(&rr->soa.serial, sizeof(rr->soa.serial), state);
1225 siphash24_compress(&rr->soa.refresh, sizeof(rr->soa.refresh), state);
1226 siphash24_compress(&rr->soa.retry, sizeof(rr->soa.retry), state);
1227 siphash24_compress(&rr->soa.expire, sizeof(rr->soa.expire), state);
1228 siphash24_compress(&rr->soa.minimum, sizeof(rr->soa.minimum), state);
1229 break;
1230
1231 case DNS_TYPE_MX:
1232 siphash24_compress(&rr->mx.priority, sizeof(rr->mx.priority), state);
1233 dns_name_hash_func(rr->mx.exchange, state);
1234 break;
1235
1236 case DNS_TYPE_LOC:
1237 siphash24_compress(&rr->loc.version, sizeof(rr->loc.version), state);
1238 siphash24_compress(&rr->loc.size, sizeof(rr->loc.size), state);
1239 siphash24_compress(&rr->loc.horiz_pre, sizeof(rr->loc.horiz_pre), state);
1240 siphash24_compress(&rr->loc.vert_pre, sizeof(rr->loc.vert_pre), state);
1241 siphash24_compress(&rr->loc.latitude, sizeof(rr->loc.latitude), state);
1242 siphash24_compress(&rr->loc.longitude, sizeof(rr->loc.longitude), state);
1243 siphash24_compress(&rr->loc.altitude, sizeof(rr->loc.altitude), state);
1244 break;
1245
1246 case DNS_TYPE_SSHFP:
1247 siphash24_compress(&rr->sshfp.algorithm, sizeof(rr->sshfp.algorithm), state);
1248 siphash24_compress(&rr->sshfp.fptype, sizeof(rr->sshfp.fptype), state);
1249 siphash24_compress(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, state);
1250 break;
1251
1252 case DNS_TYPE_DNSKEY:
1253 siphash24_compress(&rr->dnskey.flags, sizeof(rr->dnskey.flags), state);
1254 siphash24_compress(&rr->dnskey.protocol, sizeof(rr->dnskey.protocol), state);
1255 siphash24_compress(&rr->dnskey.algorithm, sizeof(rr->dnskey.algorithm), state);
1256 siphash24_compress(rr->dnskey.key, rr->dnskey.key_size, state);
1257 break;
1258
1259 case DNS_TYPE_RRSIG:
1260 siphash24_compress(&rr->rrsig.type_covered, sizeof(rr->rrsig.type_covered), state);
1261 siphash24_compress(&rr->rrsig.algorithm, sizeof(rr->rrsig.algorithm), state);
1262 siphash24_compress(&rr->rrsig.labels, sizeof(rr->rrsig.labels), state);
1263 siphash24_compress(&rr->rrsig.original_ttl, sizeof(rr->rrsig.original_ttl), state);
1264 siphash24_compress(&rr->rrsig.expiration, sizeof(rr->rrsig.expiration), state);
1265 siphash24_compress(&rr->rrsig.inception, sizeof(rr->rrsig.inception), state);
1266 siphash24_compress(&rr->rrsig.key_tag, sizeof(rr->rrsig.key_tag), state);
1267 dns_name_hash_func(rr->rrsig.signer, state);
1268 siphash24_compress(rr->rrsig.signature, rr->rrsig.signature_size, state);
1269 break;
1270
1271 case DNS_TYPE_NSEC:
1272 dns_name_hash_func(rr->nsec.next_domain_name, state);
1273 /* FIXME: we leave out the type bitmap here. Hash
1274 * would be better if we'd take it into account
1275 * too. */
1276 break;
1277
1278 case DNS_TYPE_DS:
1279 siphash24_compress(&rr->ds.key_tag, sizeof(rr->ds.key_tag), state);
1280 siphash24_compress(&rr->ds.algorithm, sizeof(rr->ds.algorithm), state);
1281 siphash24_compress(&rr->ds.digest_type, sizeof(rr->ds.digest_type), state);
1282 siphash24_compress(rr->ds.digest, rr->ds.digest_size, state);
1283 break;
1284
1285 case DNS_TYPE_NSEC3:
1286 siphash24_compress(&rr->nsec3.algorithm, sizeof(rr->nsec3.algorithm), state);
1287 siphash24_compress(&rr->nsec3.flags, sizeof(rr->nsec3.flags), state);
1288 siphash24_compress(&rr->nsec3.iterations, sizeof(rr->nsec3.iterations), state);
1289 siphash24_compress(rr->nsec3.salt, rr->nsec3.salt_size, state);
1290 siphash24_compress(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, state);
1291 /* FIXME: We leave the bitmaps out */
1292 break;
1293
1294 default:
1295 siphash24_compress(rr->generic.data, rr->generic.size, state);
1296 break;
1297 }
1298 }
1299
1300 static int dns_resource_record_compare_func(const void *a, const void *b) {
1301 const DnsResourceRecord *x = a, *y = b;
1302 int ret;
1303
1304 ret = dns_resource_key_compare_func(x->key, y->key);
1305 if (ret != 0)
1306 return ret;
1307
1308 if (dns_resource_record_equal(x, y))
1309 return 0;
1310
1311 /* This is a bit dirty, we don't implement proper odering, but
1312 * the hashtable doesn't need ordering anyway, hence we don't
1313 * care. */
1314 return x < y ? -1 : 1;
1315 }
1316
1317 const struct hash_ops dns_resource_record_hash_ops = {
1318 .hash = dns_resource_record_hash_func,
1319 .compare = dns_resource_record_compare_func,
1320 };
1321
1322 DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
1323 DnsTxtItem *n;
1324
1325 if (!i)
1326 return NULL;
1327
1328 n = i->items_next;
1329
1330 free(i);
1331 return dns_txt_item_free_all(n);
1332 }
1333
1334 bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
1335
1336 if (a == b)
1337 return true;
1338
1339 if (!a != !b)
1340 return false;
1341
1342 if (!a)
1343 return true;
1344
1345 if (a->length != b->length)
1346 return false;
1347
1348 if (memcmp(a->data, b->data, a->length) != 0)
1349 return false;
1350
1351 return dns_txt_item_equal(a->items_next, b->items_next);
1352 }
1353
1354 static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
1355 /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
1356 [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
1357 [DNSSEC_ALGORITHM_DH] = "DH",
1358 [DNSSEC_ALGORITHM_DSA] = "DSA",
1359 [DNSSEC_ALGORITHM_ECC] = "ECC",
1360 [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
1361 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1",
1362 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1",
1363 [DNSSEC_ALGORITHM_RSASHA256] = "RSASHA256",
1364 [DNSSEC_ALGORITHM_RSASHA512] = "RSASHA512",
1365 [DNSSEC_ALGORITHM_ECC_GOST] = "ECC-GOST",
1366 [DNSSEC_ALGORITHM_ECDSAP256SHA256] = "ECDSAP256SHA256",
1367 [DNSSEC_ALGORITHM_ECDSAP384SHA384] = "ECDSAP384SHA384",
1368 [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
1369 [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
1370 [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
1371 };
1372 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm, int, 255);
1373
1374 static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = {
1375 /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
1376 [DNSSEC_DIGEST_SHA1] = "SHA-1",
1377 [DNSSEC_DIGEST_SHA256] = "SHA-256",
1378 [DNSSEC_DIGEST_GOST_R_34_11_94] = "GOST_R_34.11-94",
1379 [DNSSEC_DIGEST_SHA384] = "SHA-384",
1380 };
1381 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest, int, 255);