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