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