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