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