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