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