]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-rr.c
resolved: add code to map DNSSEC digest types to strings and back
[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-util.h"
31 #include "strv.h"
32
33 DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
34 DnsResourceKey *k;
35 size_t l;
36
37 assert(name);
38
39 l = strlen(name);
40 k = malloc0(sizeof(DnsResourceKey) + l + 1);
41 if (!k)
42 return NULL;
43
44 k->n_ref = 1;
45 k->class = class;
46 k->type = type;
47
48 strcpy((char*) k + sizeof(DnsResourceKey), name);
49
50 return k;
51 }
52
53 DnsResourceKey* dns_resource_key_new_cname(const DnsResourceKey *key) {
54 assert(key);
55
56 return dns_resource_key_new(key->class, DNS_TYPE_CNAME, DNS_RESOURCE_KEY_NAME(key));
57 }
58
59 DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) {
60 int r;
61
62 assert(key);
63 assert(cname);
64
65 assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME));
66
67 if (cname->key->type == DNS_TYPE_CNAME)
68 return dns_resource_key_new(key->class, key->type, cname->cname.name);
69 else {
70 DnsResourceKey *k;
71 char *destination = NULL;
72
73 r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination);
74 if (r < 0)
75 return NULL;
76 if (r == 0)
77 return dns_resource_key_ref((DnsResourceKey*) key);
78
79 k = dns_resource_key_new_consume(key->class, key->type, destination);
80 if (!k) {
81 free(destination);
82 return NULL;
83 }
84
85 return k;
86 }
87 }
88
89 int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name) {
90 DnsResourceKey *new_key;
91 char *joined;
92 int r;
93
94 assert(ret);
95 assert(key);
96 assert(name);
97
98 if (dns_name_is_root(name)) {
99 *ret = dns_resource_key_ref(key);
100 return 0;
101 }
102
103 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), name, &joined);
104 if (r < 0)
105 return r;
106
107 new_key = dns_resource_key_new_consume(key->class, key->type, joined);
108 if (!new_key) {
109 free(joined);
110 return -ENOMEM;
111 }
112
113 *ret = new_key;
114 return 0;
115 }
116
117 DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
118 DnsResourceKey *k;
119
120 assert(name);
121
122 k = new0(DnsResourceKey, 1);
123 if (!k)
124 return NULL;
125
126 k->n_ref = 1;
127 k->class = class;
128 k->type = type;
129 k->_name = name;
130
131 return k;
132 }
133
134 DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
135
136 if (!k)
137 return NULL;
138
139 assert(k->n_ref > 0);
140 k->n_ref++;
141
142 return k;
143 }
144
145 DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
146 if (!k)
147 return NULL;
148
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 int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
161 int r;
162
163 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
164 if (r <= 0)
165 return r;
166
167 if (a->class != b->class)
168 return 0;
169
170 if (a->type != b->type)
171 return 0;
172
173 return 1;
174 }
175
176 int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain) {
177 int r;
178
179 assert(key);
180 assert(rr);
181
182 /* Checks if an rr matches the specified key. If a search
183 * domain is specified, it will also be checked if the key
184 * with the search domain suffixed might match the RR. */
185
186 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
187 return 0;
188
189 if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
190 return 0;
191
192 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
193 if (r != 0)
194 return r;
195
196 if (search_domain) {
197 _cleanup_free_ char *joined = NULL;
198
199 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
200 if (r < 0)
201 return r;
202
203 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), joined);
204 }
205
206 return 0;
207 }
208
209 int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain) {
210 int r;
211
212 assert(key);
213 assert(rr);
214
215 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
216 return 0;
217
218 if (rr->key->type == DNS_TYPE_CNAME)
219 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(rr->key));
220 else if (rr->key->type == DNS_TYPE_DNAME)
221 r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(rr->key));
222 else
223 return 0;
224
225 if (r != 0)
226 return r;
227
228 if (search_domain) {
229 _cleanup_free_ char *joined = NULL;
230
231 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
232 if (r < 0)
233 return r;
234
235 if (rr->key->type == DNS_TYPE_CNAME)
236 return dns_name_equal(joined, DNS_RESOURCE_KEY_NAME(rr->key));
237 else if (rr->key->type == DNS_TYPE_DNAME)
238 return dns_name_endswith(joined, DNS_RESOURCE_KEY_NAME(rr->key));
239 }
240
241 return 0;
242
243 }
244
245 static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
246 const DnsResourceKey *k = i;
247
248 assert(k);
249
250 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state);
251 siphash24_compress(&k->class, sizeof(k->class), state);
252 siphash24_compress(&k->type, sizeof(k->type), state);
253 }
254
255 static int dns_resource_key_compare_func(const void *a, const void *b) {
256 const DnsResourceKey *x = a, *y = b;
257 int ret;
258
259 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
260 if (ret != 0)
261 return ret;
262
263 if (x->type < y->type)
264 return -1;
265 if (x->type > y->type)
266 return 1;
267
268 if (x->class < y->class)
269 return -1;
270 if (x->class > y->class)
271 return 1;
272
273 return 0;
274 }
275
276 const struct hash_ops dns_resource_key_hash_ops = {
277 .hash = dns_resource_key_hash_func,
278 .compare = dns_resource_key_compare_func
279 };
280
281 int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
282 char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
283 const char *c, *t;
284 char *s;
285
286 c = dns_class_to_string(key->class);
287 if (!c) {
288 sprintf(cbuf, "CLASS%u", key->class);
289 c = cbuf;
290 }
291
292 t = dns_type_to_string(key->type);
293 if (!t){
294 sprintf(tbuf, "TYPE%u", key->type);
295 t = tbuf;
296 }
297
298 if (asprintf(&s, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key), c, t) < 0)
299 return -ENOMEM;
300
301 *ret = s;
302 return 0;
303 }
304
305 DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
306 DnsResourceRecord *rr;
307
308 rr = new0(DnsResourceRecord, 1);
309 if (!rr)
310 return NULL;
311
312 rr->n_ref = 1;
313 rr->key = dns_resource_key_ref(key);
314
315 return rr;
316 }
317
318 DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
319 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
320
321 key = dns_resource_key_new(class, type, name);
322 if (!key)
323 return NULL;
324
325 return dns_resource_record_new(key);
326 }
327
328 DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
329 if (!rr)
330 return NULL;
331
332 assert(rr->n_ref > 0);
333 rr->n_ref++;
334
335 return rr;
336 }
337
338 DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
339 if (!rr)
340 return NULL;
341
342 assert(rr->n_ref > 0);
343
344 if (rr->n_ref > 1) {
345 rr->n_ref--;
346 return NULL;
347 }
348
349 if (rr->key) {
350 switch(rr->key->type) {
351
352 case DNS_TYPE_SRV:
353 free(rr->srv.name);
354 break;
355
356 case DNS_TYPE_PTR:
357 case DNS_TYPE_NS:
358 case DNS_TYPE_CNAME:
359 case DNS_TYPE_DNAME:
360 free(rr->ptr.name);
361 break;
362
363 case DNS_TYPE_HINFO:
364 free(rr->hinfo.cpu);
365 free(rr->hinfo.os);
366 break;
367
368 case DNS_TYPE_TXT:
369 case DNS_TYPE_SPF:
370 dns_txt_item_free_all(rr->txt.items);
371 break;
372
373 case DNS_TYPE_SOA:
374 free(rr->soa.mname);
375 free(rr->soa.rname);
376 break;
377
378 case DNS_TYPE_MX:
379 free(rr->mx.exchange);
380 break;
381
382 case DNS_TYPE_DS:
383 free(rr->ds.digest);
384 break;
385
386 case DNS_TYPE_SSHFP:
387 free(rr->sshfp.fingerprint);
388 break;
389
390 case DNS_TYPE_DNSKEY:
391 free(rr->dnskey.key);
392 break;
393
394 case DNS_TYPE_RRSIG:
395 free(rr->rrsig.signer);
396 free(rr->rrsig.signature);
397 break;
398
399 case DNS_TYPE_NSEC:
400 free(rr->nsec.next_domain_name);
401 bitmap_free(rr->nsec.types);
402 break;
403
404 case DNS_TYPE_NSEC3:
405 free(rr->nsec3.next_hashed_name);
406 free(rr->nsec3.salt);
407 bitmap_free(rr->nsec3.types);
408 break;
409
410 case DNS_TYPE_LOC:
411 case DNS_TYPE_A:
412 case DNS_TYPE_AAAA:
413 break;
414
415 default:
416 free(rr->generic.data);
417 }
418
419 dns_resource_key_unref(rr->key);
420 }
421
422 free(rr);
423
424 return NULL;
425 }
426
427 int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
428 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
429 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
430 _cleanup_free_ char *ptr = NULL;
431 int r;
432
433 assert(ret);
434 assert(address);
435 assert(hostname);
436
437 r = dns_name_reverse(family, address, &ptr);
438 if (r < 0)
439 return r;
440
441 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
442 if (!key)
443 return -ENOMEM;
444
445 ptr = NULL;
446
447 rr = dns_resource_record_new(key);
448 if (!rr)
449 return -ENOMEM;
450
451 rr->ptr.name = strdup(hostname);
452 if (!rr->ptr.name)
453 return -ENOMEM;
454
455 *ret = rr;
456 rr = NULL;
457
458 return 0;
459 }
460
461 int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
462 DnsResourceRecord *rr;
463
464 assert(ret);
465 assert(address);
466 assert(family);
467
468 if (family == AF_INET) {
469
470 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
471 if (!rr)
472 return -ENOMEM;
473
474 rr->a.in_addr = address->in;
475
476 } else if (family == AF_INET6) {
477
478 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
479 if (!rr)
480 return -ENOMEM;
481
482 rr->aaaa.in6_addr = address->in6;
483 } else
484 return -EAFNOSUPPORT;
485
486 *ret = rr;
487
488 return 0;
489 }
490
491 int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
492 int r;
493
494 assert(a);
495 assert(b);
496
497 r = dns_resource_key_equal(a->key, b->key);
498 if (r <= 0)
499 return r;
500
501 if (a->unparseable != b->unparseable)
502 return 0;
503
504 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
505
506 case DNS_TYPE_SRV:
507 r = dns_name_equal(a->srv.name, b->srv.name);
508 if (r <= 0)
509 return r;
510
511 return a->srv.priority == b->srv.priority &&
512 a->srv.weight == b->srv.weight &&
513 a->srv.port == b->srv.port;
514
515 case DNS_TYPE_PTR:
516 case DNS_TYPE_NS:
517 case DNS_TYPE_CNAME:
518 case DNS_TYPE_DNAME:
519 return dns_name_equal(a->ptr.name, b->ptr.name);
520
521 case DNS_TYPE_HINFO:
522 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
523 strcaseeq(a->hinfo.os, b->hinfo.os);
524
525 case DNS_TYPE_SPF: /* exactly the same as TXT */
526 case DNS_TYPE_TXT:
527 return dns_txt_item_equal(a->txt.items, b->txt.items);
528
529 case DNS_TYPE_A:
530 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
531
532 case DNS_TYPE_AAAA:
533 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
534
535 case DNS_TYPE_SOA:
536 r = dns_name_equal(a->soa.mname, b->soa.mname);
537 if (r <= 0)
538 return r;
539 r = dns_name_equal(a->soa.rname, b->soa.rname);
540 if (r <= 0)
541 return r;
542
543 return a->soa.serial == b->soa.serial &&
544 a->soa.refresh == b->soa.refresh &&
545 a->soa.retry == b->soa.retry &&
546 a->soa.expire == b->soa.expire &&
547 a->soa.minimum == b->soa.minimum;
548
549 case DNS_TYPE_MX:
550 if (a->mx.priority != b->mx.priority)
551 return 0;
552
553 return dns_name_equal(a->mx.exchange, b->mx.exchange);
554
555 case DNS_TYPE_LOC:
556 assert(a->loc.version == b->loc.version);
557
558 return a->loc.size == b->loc.size &&
559 a->loc.horiz_pre == b->loc.horiz_pre &&
560 a->loc.vert_pre == b->loc.vert_pre &&
561 a->loc.latitude == b->loc.latitude &&
562 a->loc.longitude == b->loc.longitude &&
563 a->loc.altitude == b->loc.altitude;
564
565 case DNS_TYPE_DS:
566 return a->ds.key_tag == b->ds.key_tag &&
567 a->ds.algorithm == b->ds.algorithm &&
568 a->ds.digest_type == b->ds.digest_type &&
569 a->ds.digest_size == b->ds.digest_size &&
570 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
571
572 case DNS_TYPE_SSHFP:
573 return a->sshfp.algorithm == b->sshfp.algorithm &&
574 a->sshfp.fptype == b->sshfp.fptype &&
575 a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
576 memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
577
578 case DNS_TYPE_DNSKEY:
579 return a->dnskey.flags == b->dnskey.flags &&
580 a->dnskey.protocol == b->dnskey.protocol &&
581 a->dnskey.algorithm == b->dnskey.algorithm &&
582 a->dnskey.key_size == b->dnskey.key_size &&
583 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
584
585 case DNS_TYPE_RRSIG:
586 /* do the fast comparisons first */
587 if (a->rrsig.type_covered != b->rrsig.type_covered ||
588 a->rrsig.algorithm != b->rrsig.algorithm ||
589 a->rrsig.labels != b->rrsig.labels ||
590 a->rrsig.original_ttl != b->rrsig.original_ttl ||
591 a->rrsig.expiration != b->rrsig.expiration ||
592 a->rrsig.inception != b->rrsig.inception ||
593 a->rrsig.key_tag != b->rrsig.key_tag ||
594 a->rrsig.signature_size != b->rrsig.signature_size ||
595 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
596 return false;
597
598 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
599
600 case DNS_TYPE_NSEC:
601 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
602 bitmap_equal(a->nsec.types, b->nsec.types);
603
604 case DNS_TYPE_NSEC3:
605 return a->nsec3.algorithm == b->nsec3.algorithm &&
606 a->nsec3.flags == b->nsec3.flags &&
607 a->nsec3.iterations == b->nsec3.iterations &&
608 a->nsec3.salt_size == b->nsec3.salt_size &&
609 memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
610 memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
611 bitmap_equal(a->nsec3.types, b->nsec3.types);
612
613 default:
614 return a->generic.size == b->generic.size &&
615 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
616 }
617 }
618
619 static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
620 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
621 char *s;
622 char NS = latitude >= 1U<<31 ? 'N' : 'S';
623 char EW = longitude >= 1U<<31 ? 'E' : 'W';
624
625 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
626 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
627 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
628 double siz = (size >> 4) * exp10((double) (size & 0xF));
629 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
630 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
631
632 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
633 (lat / 60000 / 60),
634 (lat / 60000) % 60,
635 (lat % 60000) / 1000.,
636 NS,
637 (lon / 60000 / 60),
638 (lon / 60000) % 60,
639 (lon % 60000) / 1000.,
640 EW,
641 alt / 100.,
642 siz / 100.,
643 hor / 100.,
644 ver / 100.) < 0)
645 return NULL;
646
647 return s;
648 }
649
650 static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
651 struct tm tm;
652
653 assert(buf);
654 assert(l > strlen("YYYYMMDDHHmmSS"));
655
656 if (!gmtime_r(&sec, &tm))
657 return -EINVAL;
658
659 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
660 return -EINVAL;
661
662 return 0;
663 }
664
665 static char *format_types(Bitmap *types) {
666 _cleanup_strv_free_ char **strv = NULL;
667 _cleanup_free_ char *str = NULL;
668 Iterator i;
669 unsigned type;
670 int r;
671
672 BITMAP_FOREACH(type, types, i) {
673 if (dns_type_to_string(type)) {
674 r = strv_extend(&strv, dns_type_to_string(type));
675 if (r < 0)
676 return NULL;
677 } else {
678 char *t;
679
680 r = asprintf(&t, "TYPE%u", type);
681 if (r < 0)
682 return NULL;
683
684 r = strv_consume(&strv, t);
685 if (r < 0)
686 return NULL;
687 }
688 }
689
690 str = strv_join(strv, " ");
691 if (!str)
692 return NULL;
693
694 return strjoin("( ", str, " )", NULL);
695 }
696
697 static char *format_txt(DnsTxtItem *first) {
698 DnsTxtItem *i;
699 size_t c = 1;
700 char *p, *s;
701
702 LIST_FOREACH(items, i, first)
703 c += i->length * 4 + 3;
704
705 p = s = new(char, c);
706 if (!s)
707 return NULL;
708
709 LIST_FOREACH(items, i, first) {
710 size_t j;
711
712 if (i != first)
713 *(p++) = ' ';
714
715 *(p++) = '"';
716
717 for (j = 0; j < i->length; j++) {
718 if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) {
719 *(p++) = '\\';
720 *(p++) = '0' + (i->data[j] / 100);
721 *(p++) = '0' + ((i->data[j] / 10) % 10);
722 *(p++) = '0' + (i->data[j] % 10);
723 } else
724 *(p++) = i->data[j];
725 }
726
727 *(p++) = '"';
728 }
729
730 *p = 0;
731 return s;
732 }
733
734 int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
735 _cleanup_free_ char *k = NULL, *t = NULL;
736 char *s;
737 int r;
738
739 assert(rr);
740
741 r = dns_resource_key_to_string(rr->key, &k);
742 if (r < 0)
743 return r;
744
745 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
746
747 case DNS_TYPE_SRV:
748 r = asprintf(&s, "%s %u %u %u %s",
749 k,
750 rr->srv.priority,
751 rr->srv.weight,
752 rr->srv.port,
753 strna(rr->srv.name));
754 if (r < 0)
755 return -ENOMEM;
756 break;
757
758 case DNS_TYPE_PTR:
759 case DNS_TYPE_NS:
760 case DNS_TYPE_CNAME:
761 case DNS_TYPE_DNAME:
762 s = strjoin(k, " ", rr->ptr.name, NULL);
763 if (!s)
764 return -ENOMEM;
765
766 break;
767
768 case DNS_TYPE_HINFO:
769 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
770 if (!s)
771 return -ENOMEM;
772 break;
773
774 case DNS_TYPE_SPF: /* exactly the same as TXT */
775 case DNS_TYPE_TXT:
776 t = format_txt(rr->txt.items);
777 if (!t)
778 return -ENOMEM;
779
780 s = strjoin(k, " ", t, NULL);
781 if (!s)
782 return -ENOMEM;
783 break;
784
785 case DNS_TYPE_A: {
786 _cleanup_free_ char *x = NULL;
787
788 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
789 if (r < 0)
790 return r;
791
792 s = strjoin(k, " ", x, NULL);
793 if (!s)
794 return -ENOMEM;
795 break;
796 }
797
798 case DNS_TYPE_AAAA:
799 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
800 if (r < 0)
801 return r;
802
803 s = strjoin(k, " ", t, NULL);
804 if (!s)
805 return -ENOMEM;
806 break;
807
808 case DNS_TYPE_SOA:
809 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
810 k,
811 strna(rr->soa.mname),
812 strna(rr->soa.rname),
813 rr->soa.serial,
814 rr->soa.refresh,
815 rr->soa.retry,
816 rr->soa.expire,
817 rr->soa.minimum);
818 if (r < 0)
819 return -ENOMEM;
820 break;
821
822 case DNS_TYPE_MX:
823 r = asprintf(&s, "%s %u %s",
824 k,
825 rr->mx.priority,
826 rr->mx.exchange);
827 if (r < 0)
828 return -ENOMEM;
829 break;
830
831 case DNS_TYPE_LOC:
832 assert(rr->loc.version == 0);
833
834 t = format_location(rr->loc.latitude,
835 rr->loc.longitude,
836 rr->loc.altitude,
837 rr->loc.size,
838 rr->loc.horiz_pre,
839 rr->loc.vert_pre);
840 if (!t)
841 return -ENOMEM;
842
843 s = strjoin(k, " ", t, NULL);
844 if (!s)
845 return -ENOMEM;
846 break;
847
848 case DNS_TYPE_DS:
849 t = hexmem(rr->ds.digest, rr->ds.digest_size);
850 if (!t)
851 return -ENOMEM;
852
853 r = asprintf(&s, "%s %u %u %u %s",
854 k,
855 rr->ds.key_tag,
856 rr->ds.algorithm,
857 rr->ds.digest_type,
858 t);
859 if (r < 0)
860 return -ENOMEM;
861 break;
862
863 case DNS_TYPE_SSHFP:
864 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
865 if (!t)
866 return -ENOMEM;
867
868 r = asprintf(&s, "%s %u %u %s",
869 k,
870 rr->sshfp.algorithm,
871 rr->sshfp.fptype,
872 t);
873 if (r < 0)
874 return -ENOMEM;
875 break;
876
877 case DNS_TYPE_DNSKEY: {
878 const char *alg;
879
880 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
881
882 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
883 if (!t)
884 return -ENOMEM;
885
886 r = asprintf(&s, "%s %u %u %.*s%.*u %s",
887 k,
888 rr->dnskey.flags,
889 rr->dnskey.protocol,
890 alg ? -1 : 0, alg,
891 alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
892 t);
893 if (r < 0)
894 return -ENOMEM;
895 break;
896 }
897
898 case DNS_TYPE_RRSIG: {
899 const char *type, *alg;
900 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
901
902 type = dns_type_to_string(rr->rrsig.type_covered);
903 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
904
905 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
906 if (!t)
907 return -ENOMEM;
908
909 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
910 if (r < 0)
911 return r;
912
913 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
914 if (r < 0)
915 return r;
916
917 /* TYPE?? follows
918 * http://tools.ietf.org/html/rfc3597#section-5 */
919
920 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
921 k,
922 type ?: "TYPE",
923 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
924 alg ? -1 : 0, alg,
925 alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
926 rr->rrsig.labels,
927 rr->rrsig.original_ttl,
928 expiration,
929 inception,
930 rr->rrsig.key_tag,
931 rr->rrsig.signer,
932 t);
933 if (r < 0)
934 return -ENOMEM;
935 break;
936 }
937
938 case DNS_TYPE_NSEC:
939 t = format_types(rr->nsec.types);
940 if (!t)
941 return -ENOMEM;
942
943 r = asprintf(&s, "%s %s %s",
944 k,
945 rr->nsec.next_domain_name,
946 t);
947 if (r < 0)
948 return -ENOMEM;
949 break;
950
951 case DNS_TYPE_NSEC3: {
952 _cleanup_free_ char *salt = NULL, *hash = NULL;
953
954 if (rr->nsec3.salt_size > 0) {
955 salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
956 if (!salt)
957 return -ENOMEM;
958 }
959
960 hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
961 if (!hash)
962 return -ENOMEM;
963
964 t = format_types(rr->nsec3.types);
965 if (!t)
966 return -ENOMEM;
967
968 r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
969 k,
970 rr->nsec3.algorithm,
971 rr->nsec3.flags,
972 rr->nsec3.iterations,
973 rr->nsec3.salt_size > 0 ? salt : "-",
974 hash,
975 t);
976 if (r < 0)
977 return -ENOMEM;
978
979 break;
980 }
981
982 default:
983 t = hexmem(rr->generic.data, rr->generic.size);
984 if (!t)
985 return -ENOMEM;
986
987 r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
988 if (r < 0)
989 return -ENOMEM;
990 break;
991 }
992
993 *ret = s;
994 return 0;
995 }
996
997 const char *dns_class_to_string(uint16_t class) {
998
999 switch (class) {
1000
1001 case DNS_CLASS_IN:
1002 return "IN";
1003
1004 case DNS_CLASS_ANY:
1005 return "ANY";
1006 }
1007
1008 return NULL;
1009 }
1010
1011 int dns_class_from_string(const char *s, uint16_t *class) {
1012 assert(s);
1013 assert(class);
1014
1015 if (strcaseeq(s, "IN"))
1016 *class = DNS_CLASS_IN;
1017 else if (strcaseeq(s, "ANY"))
1018 *class = DNS_CLASS_ANY;
1019 else
1020 return -EINVAL;
1021
1022 return 0;
1023 }
1024
1025 DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
1026 DnsTxtItem *n;
1027
1028 if (!i)
1029 return NULL;
1030
1031 n = i->items_next;
1032
1033 free(i);
1034 return dns_txt_item_free_all(n);
1035 }
1036
1037 bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
1038
1039 if (!a != !b)
1040 return false;
1041
1042 if (!a)
1043 return true;
1044
1045 if (a->length != b->length)
1046 return false;
1047
1048 if (memcmp(a->data, b->data, a->length) != 0)
1049 return false;
1050
1051 return dns_txt_item_equal(a->items_next, b->items_next);
1052 }