basic: util - add base32hexmem() function similar to hexmem()
[thirdparty/systemd.git] / src / resolve / resolved-dns-rr.c
CommitLineData
74b2466e
LP
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
0dae31d4
ZJS
22#include <math.h>
23
2e276efc
ZJS
24#include "strv.h"
25
4ad7f276 26#include "dns-domain.h"
74b2466e 27#include "resolved-dns-rr.h"
8db0d2f5 28#include "resolved-dns-packet.h"
7263f724 29#include "dns-type.h"
74b2466e 30
faa133f3
LP
31DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
32 DnsResourceKey *k;
33 size_t l;
74b2466e 34
faa133f3
LP
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_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
68DnsResourceKey* 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
79DnsResourceKey* 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
94int 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
110int 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
123int 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));
74b2466e
LP
134}
135
d5099efc 136static unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]) {
322345fd
LP
137 const DnsResourceKey *k = i;
138 unsigned long ul;
139
faa133f3 140 ul = dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), hash_key);
322345fd
LP
141 ul = ul * hash_key[0] + ul + k->class;
142 ul = ul * hash_key[1] + ul + k->type;
143
144 return ul;
145}
146
d5099efc 147static int dns_resource_key_compare_func(const void *a, const void *b) {
322345fd
LP
148 const DnsResourceKey *x = a, *y = b;
149 int ret;
150
faa133f3 151 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
322345fd
LP
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
d5099efc
MS
168const struct hash_ops dns_resource_key_hash_ops = {
169 .hash = dns_resource_key_hash_func,
170 .compare = dns_resource_key_compare_func
171};
172
2d4c5cbc 173int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
d23a27a9 174 char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
2d4c5cbc
LP
175 const char *c, *t;
176 char *s;
177
178 c = dns_class_to_string(key->class);
179 if (!c) {
d23a27a9 180 sprintf(cbuf, "CLASS%u", key->class);
2d4c5cbc
LP
181 c = cbuf;
182 }
183
184 t = dns_type_to_string(key->type);
185 if (!t){
d23a27a9 186 sprintf(tbuf, "TYPE%u", key->type);
2d4c5cbc
LP
187 t = tbuf;
188 }
189
23432a1c 190 if (asprintf(&s, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key), c, t) < 0)
2d4c5cbc
LP
191 return -ENOMEM;
192
193 *ret = s;
194 return 0;
195}
196
faa133f3 197DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
74b2466e
LP
198 DnsResourceRecord *rr;
199
200 rr = new0(DnsResourceRecord, 1);
201 if (!rr)
202 return NULL;
203
204 rr->n_ref = 1;
faa133f3
LP
205 rr->key = dns_resource_key_ref(key);
206
74b2466e
LP
207 return rr;
208}
209
8bf52d3d
LP
210DnsResourceRecord* 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
74b2466e
LP
220DnsResourceRecord* 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
230DnsResourceRecord* 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
faa133f3 241 if (rr->key) {
9de3e329 242 switch(rr->key->type) {
9c92ce6d
LP
243
244 case DNS_TYPE_SRV:
245 free(rr->srv.name);
246 break;
247
9de3e329
ZJS
248 case DNS_TYPE_PTR:
249 case DNS_TYPE_NS:
250 case DNS_TYPE_CNAME:
8ac4e9e1 251 case DNS_TYPE_DNAME:
faa133f3 252 free(rr->ptr.name);
9de3e329 253 break;
9c92ce6d 254
9de3e329 255 case DNS_TYPE_HINFO:
faa133f3
LP
256 free(rr->hinfo.cpu);
257 free(rr->hinfo.os);
9de3e329 258 break;
9c92ce6d 259
9de3e329 260 case DNS_TYPE_TXT:
9c92ce6d 261 case DNS_TYPE_SPF:
2e276efc 262 strv_free(rr->txt.strings);
9de3e329 263 break;
9c92ce6d 264
9de3e329 265 case DNS_TYPE_SOA:
7e8e0422
LP
266 free(rr->soa.mname);
267 free(rr->soa.rname);
9de3e329 268 break;
9c92ce6d 269
9de3e329 270 case DNS_TYPE_MX:
946c7094 271 free(rr->mx.exchange);
9de3e329 272 break;
9c92ce6d 273
abf126a3
TG
274 case DNS_TYPE_DS:
275 free(rr->ds.digest);
276 break;
277
42cc2eeb
LP
278 case DNS_TYPE_SSHFP:
279 free(rr->sshfp.key);
280 break;
281
8db0d2f5
ZJS
282 case DNS_TYPE_DNSKEY:
283 free(rr->dnskey.key);
284 break;
285
151226ab
ZJS
286 case DNS_TYPE_RRSIG:
287 free(rr->rrsig.signer);
288 free(rr->rrsig.signature);
289 break;
290
50f1e641
TG
291 case DNS_TYPE_NSEC:
292 free(rr->nsec.next_domain_name);
293 bitmap_free(rr->nsec.types);
294 break;
295
0dae31d4 296 case DNS_TYPE_LOC:
9de3e329
ZJS
297 case DNS_TYPE_A:
298 case DNS_TYPE_AAAA:
299 break;
9c92ce6d 300
9de3e329 301 default:
faa133f3 302 free(rr->generic.data);
9de3e329 303 }
322345fd 304
faa133f3
LP
305 dns_resource_key_unref(rr->key);
306 }
322345fd 307
faa133f3 308 free(rr);
322345fd 309
322345fd
LP
310 return NULL;
311}
312
623a4c97
LP
313int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
314 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
315 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
316 _cleanup_free_ char *ptr = NULL;
317 int r;
318
319 assert(ret);
320 assert(address);
321 assert(hostname);
322
323 r = dns_name_reverse(family, address, &ptr);
324 if (r < 0)
325 return r;
326
327 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
328 if (!key)
329 return -ENOMEM;
330
331 ptr = NULL;
332
333 rr = dns_resource_record_new(key);
334 if (!rr)
335 return -ENOMEM;
336
337 rr->ptr.name = strdup(hostname);
338 if (!rr->ptr.name)
339 return -ENOMEM;
340
341 *ret = rr;
342 rr = NULL;
343
344 return 0;
345}
346
322345fd
LP
347int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
348 int r;
349
350 assert(a);
351 assert(b);
352
faa133f3 353 r = dns_resource_key_equal(a->key, b->key);
322345fd
LP
354 if (r <= 0)
355 return r;
356
fd0b4602
LP
357 if (a->unparseable != b->unparseable)
358 return 0;
359
360 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
2d4c5cbc 361
9c92ce6d
LP
362 case DNS_TYPE_SRV:
363 r = dns_name_equal(a->srv.name, b->srv.name);
364 if (r <= 0)
365 return r;
366
367 return a->srv.priority == b->srv.priority &&
368 a->srv.weight == b->srv.weight &&
369 a->srv.port == b->srv.port;
370
2d4c5cbc
LP
371 case DNS_TYPE_PTR:
372 case DNS_TYPE_NS:
373 case DNS_TYPE_CNAME:
8ac4e9e1 374 case DNS_TYPE_DNAME:
322345fd 375 return dns_name_equal(a->ptr.name, b->ptr.name);
2d4c5cbc
LP
376
377 case DNS_TYPE_HINFO:
378 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
379 strcaseeq(a->hinfo.os, b->hinfo.os);
380
9de3e329 381 case DNS_TYPE_SPF: /* exactly the same as TXT */
0f84a72e
DH
382 case DNS_TYPE_TXT:
383 return strv_equal(a->txt.strings, b->txt.strings);
2e276efc 384
2d4c5cbc 385 case DNS_TYPE_A:
322345fd 386 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
2d4c5cbc
LP
387
388 case DNS_TYPE_AAAA:
322345fd 389 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
2d4c5cbc
LP
390
391 case DNS_TYPE_SOA:
7e8e0422
LP
392 r = dns_name_equal(a->soa.mname, b->soa.mname);
393 if (r <= 0)
394 return r;
395 r = dns_name_equal(a->soa.rname, b->soa.rname);
396 if (r <= 0)
397 return r;
398
399 return a->soa.serial == b->soa.serial &&
400 a->soa.refresh == b->soa.refresh &&
401 a->soa.retry == b->soa.retry &&
402 a->soa.expire == b->soa.expire &&
403 a->soa.minimum == b->soa.minimum;
9c92ce6d 404
946c7094
ZJS
405 case DNS_TYPE_MX:
406 if (a->mx.priority != b->mx.priority)
407 return 0;
408
409 return dns_name_equal(a->mx.exchange, b->mx.exchange);
410
0dae31d4
ZJS
411 case DNS_TYPE_LOC:
412 assert(a->loc.version == b->loc.version);
413
414 return a->loc.size == b->loc.size &&
415 a->loc.horiz_pre == b->loc.horiz_pre &&
416 a->loc.vert_pre == b->loc.vert_pre &&
417 a->loc.latitude == b->loc.latitude &&
418 a->loc.longitude == b->loc.longitude &&
419 a->loc.altitude == b->loc.altitude;
420
abf126a3
TG
421 case DNS_TYPE_DS:
422 return a->ds.key_tag == b->ds.key_tag &&
423 a->ds.algorithm == b->ds.algorithm &&
424 a->ds.digest_type == b->ds.digest_type &&
425 a->ds.digest_size == b->ds.digest_size &&
426 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
427
42cc2eeb
LP
428 case DNS_TYPE_SSHFP:
429 return a->sshfp.algorithm == b->sshfp.algorithm &&
430 a->sshfp.fptype == b->sshfp.fptype &&
431 a->sshfp.key_size == b->sshfp.key_size &&
432 memcmp(a->sshfp.key, b->sshfp.key, a->sshfp.key_size) == 0;
433
8db0d2f5
ZJS
434 case DNS_TYPE_DNSKEY:
435 return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag &&
436 a->dnskey.sep_flag == b->dnskey.sep_flag &&
437 a->dnskey.algorithm == b->dnskey.algorithm &&
438 a->dnskey.key_size == b->dnskey.key_size &&
439 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
440
151226ab
ZJS
441 case DNS_TYPE_RRSIG:
442 /* do the fast comparisons first */
03664a62
LN
443 if (a->rrsig.type_covered != b->rrsig.type_covered ||
444 a->rrsig.algorithm != b->rrsig.algorithm ||
445 a->rrsig.labels != b->rrsig.labels ||
446 a->rrsig.original_ttl != b->rrsig.original_ttl ||
447 a->rrsig.expiration != b->rrsig.expiration ||
448 a->rrsig.inception != b->rrsig.inception ||
449 a->rrsig.key_tag != b->rrsig.key_tag ||
151226ab
ZJS
450 a->rrsig.signature_size != b->rrsig.signature_size ||
451 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
452 return false;
453
454 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
455
50f1e641
TG
456 case DNS_TYPE_NSEC:
457 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
458 bitmap_equal(a->nsec.types, b->nsec.types);
459
2d4c5cbc 460 default:
322345fd
LP
461 return a->generic.size == b->generic.size &&
462 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
2d4c5cbc 463 }
322345fd
LP
464}
465
0dae31d4
ZJS
466static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
467 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
468 char *s;
469 char NS = latitude >= 1U<<31 ? 'N' : 'S';
470 char EW = longitude >= 1U<<31 ? 'E' : 'W';
471
472 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
473 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
474 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
475 double siz = (size >> 4) * exp10((double) (size & 0xF));
476 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
477 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
478
479 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
480 (lat / 60000 / 60),
481 (lat / 60000) % 60,
482 (lat % 60000) / 1000.,
483 NS,
484 (lon / 60000 / 60),
485 (lon / 60000) % 60,
486 (lon % 60000) / 1000.,
487 EW,
488 alt / 100.,
489 siz / 100.,
490 hor / 100.,
491 ver / 100.) < 0)
492 return NULL;
493
494 return s;
495}
496
7c6423e1
TG
497static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
498 struct tm tm;
499
500 assert(buf);
501 assert(l > strlen("YYYYMMDDHHmmSS"));
502
503 if (!gmtime_r(&sec, &tm))
504 return -EINVAL;
505
506 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
507 return -EINVAL;
508
509 return 0;
510}
511
50f1e641
TG
512static char *format_types(Bitmap *types) {
513 _cleanup_strv_free_ char **strv = NULL;
514 _cleanup_free_ char *str = NULL;
515 unsigned type;
516 int r;
517
518 BITMAP_FOREACH(type, types) {
519 if (dns_type_to_string(type)) {
520 r = strv_extend(&strv, strdup(dns_type_to_string(type)));
521 if (r < 0)
522 return NULL;
523 } else {
524 char *t;
525
526 r = asprintf(&t, "TYPE%u", type);
527 if (r < 0)
528 return NULL;
529
530 r = strv_extend(&strv, t);
531 if (r < 0)
532 return NULL;
533 }
534 }
535
536 str = strv_join(strv, " ");
537 if (!str)
538 return NULL;
539
540 return strjoin("( ", str, " )", NULL);
541}
542
2d4c5cbc 543int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
8db0d2f5 544 _cleanup_free_ char *k = NULL, *t = NULL;
2d4c5cbc
LP
545 char *s;
546 int r;
322345fd 547
2d4c5cbc 548 assert(rr);
322345fd 549
2d4c5cbc
LP
550 r = dns_resource_key_to_string(rr->key, &k);
551 if (r < 0)
552 return r;
322345fd 553
0dae31d4 554 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
322345fd 555
9c92ce6d
LP
556 case DNS_TYPE_SRV:
557 r = asprintf(&s, "%s %u %u %u %s",
558 k,
559 rr->srv.priority,
560 rr->srv.weight,
561 rr->srv.port,
562 strna(rr->srv.name));
563 if (r < 0)
564 return -ENOMEM;
565 break;
566
2d4c5cbc
LP
567 case DNS_TYPE_PTR:
568 case DNS_TYPE_NS:
569 case DNS_TYPE_CNAME:
8ac4e9e1 570 case DNS_TYPE_DNAME:
2d4c5cbc
LP
571 s = strjoin(k, " ", rr->ptr.name, NULL);
572 if (!s)
573 return -ENOMEM;
322345fd 574
2d4c5cbc 575 break;
322345fd 576
2d4c5cbc
LP
577 case DNS_TYPE_HINFO:
578 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
579 if (!s)
580 return -ENOMEM;
581 break;
322345fd 582
9de3e329 583 case DNS_TYPE_SPF: /* exactly the same as TXT */
8db0d2f5 584 case DNS_TYPE_TXT:
2e276efc
ZJS
585 t = strv_join_quoted(rr->txt.strings);
586 if (!t)
587 return -ENOMEM;
588
589 s = strjoin(k, " ", t, NULL);
590 if (!s)
591 return -ENOMEM;
592
593 break;
2e276efc 594
2d4c5cbc
LP
595 case DNS_TYPE_A: {
596 _cleanup_free_ char *x = NULL;
322345fd 597
2d4c5cbc
LP
598 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
599 if (r < 0)
600 return r;
322345fd 601
2d4c5cbc
LP
602 s = strjoin(k, " ", x, NULL);
603 if (!s)
604 return -ENOMEM;
605 break;
606 }
322345fd 607
8db0d2f5
ZJS
608 case DNS_TYPE_AAAA:
609 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
2d4c5cbc
LP
610 if (r < 0)
611 return r;
322345fd 612
8db0d2f5 613 s = strjoin(k, " ", t, NULL);
2d4c5cbc
LP
614 if (!s)
615 return -ENOMEM;
616 break;
322345fd 617
2d4c5cbc
LP
618 case DNS_TYPE_SOA:
619 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
620 k,
621 strna(rr->soa.mname),
622 strna(rr->soa.rname),
623 rr->soa.serial,
624 rr->soa.refresh,
625 rr->soa.retry,
626 rr->soa.expire,
627 rr->soa.minimum);
628 if (r < 0)
629 return -ENOMEM;
630 break;
631
946c7094
ZJS
632 case DNS_TYPE_MX:
633 r = asprintf(&s, "%s %u %s",
634 k,
635 rr->mx.priority,
636 rr->mx.exchange);
637 if (r < 0)
638 return -ENOMEM;
639 break;
640
8db0d2f5 641 case DNS_TYPE_LOC:
0dae31d4
ZJS
642 assert(rr->loc.version == 0);
643
8db0d2f5
ZJS
644 t = format_location(rr->loc.latitude,
645 rr->loc.longitude,
646 rr->loc.altitude,
647 rr->loc.size,
648 rr->loc.horiz_pre,
649 rr->loc.vert_pre);
650 if (!t)
0dae31d4
ZJS
651 return -ENOMEM;
652
8db0d2f5 653 s = strjoin(k, " ", t, NULL);
0dae31d4
ZJS
654 if (!s)
655 return -ENOMEM;
0dae31d4 656 break;
0dae31d4 657
abf126a3
TG
658 case DNS_TYPE_DS:
659 t = hexmem(rr->ds.digest, rr->ds.digest_size);
660 if (!t)
661 return -ENOMEM;
662
663 r = asprintf(&s, "%s %u %u %u %s",
664 k,
665 rr->ds.key_tag,
666 rr->ds.algorithm,
667 rr->ds.digest_type,
668 t);
669 if (r < 0)
670 return -ENOMEM;
671 break;
672
8db0d2f5
ZJS
673 case DNS_TYPE_SSHFP:
674 t = hexmem(rr->sshfp.key, rr->sshfp.key_size);
675 if (!t)
42cc2eeb
LP
676 return -ENOMEM;
677
678 r = asprintf(&s, "%s %u %u %s",
679 k,
680 rr->sshfp.algorithm,
681 rr->sshfp.fptype,
8db0d2f5 682 t);
42cc2eeb
LP
683 if (r < 0)
684 return -ENOMEM;
685 break;
42cc2eeb 686
ff3d6560
ZJS
687 case DNS_TYPE_DNSKEY: {
688 const char *alg;
689
690 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
691
1bf968f3 692 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
8db0d2f5
ZJS
693 if (!t)
694 return -ENOMEM;
2d4c5cbc 695
ff3d6560 696 r = asprintf(&s, "%s %u 3 %.*s%.*u %s",
8db0d2f5
ZJS
697 k,
698 dnskey_to_flags(rr),
ff3d6560
ZJS
699 alg ? -1 : 0, alg,
700 alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
8db0d2f5
ZJS
701 t);
702 if (r < 0)
2d4c5cbc 703 return -ENOMEM;
8db0d2f5 704 break;
ff3d6560 705 }
2d4c5cbc 706
151226ab
ZJS
707 case DNS_TYPE_RRSIG: {
708 const char *type, *alg;
7c6423e1 709 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
151226ab
ZJS
710
711 type = dns_type_to_string(rr->rrsig.type_covered);
712 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
713
1bf968f3 714 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
151226ab
ZJS
715 if (!t)
716 return -ENOMEM;
717
7c6423e1
TG
718 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
719 if (r < 0)
720 return r;
721
722 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
723 if (r < 0)
724 return r;
725
151226ab
ZJS
726 /* TYPE?? follows
727 * http://tools.ietf.org/html/rfc3597#section-5 */
728
7c6423e1 729 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
151226ab
ZJS
730 k,
731 type ?: "TYPE",
732 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
733 alg ? -1 : 0, alg,
734 alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
735 rr->rrsig.labels,
736 rr->rrsig.original_ttl,
7c6423e1
TG
737 expiration,
738 inception,
151226ab
ZJS
739 rr->rrsig.key_tag,
740 rr->rrsig.signer,
741 t);
742 if (r < 0)
743 return -ENOMEM;
744 break;
745 }
746
50f1e641
TG
747 case DNS_TYPE_NSEC:
748 t = format_types(rr->nsec.types);
749 if (!t)
750 return -ENOMEM;
751
752 r = asprintf(&s, "%s %s %s",
753 k,
754 rr->nsec.next_domain_name,
755 t);
756 if (r < 0)
757 return -ENOMEM;
758 break;
759
8db0d2f5
ZJS
760 default:
761 t = hexmem(rr->generic.data, rr->generic.size);
762 if (!t)
763 return -ENOMEM;
764
d23a27a9
TG
765 r = asprintf(&s, "%s \\# %"PRIu8" %s", k, rr->generic.size, t);
766 if (r < 0)
2d4c5cbc
LP
767 return -ENOMEM;
768 break;
8db0d2f5 769 }
2d4c5cbc
LP
770
771 *ret = s;
772 return 0;
773}
322345fd 774
2d4c5cbc 775const char *dns_class_to_string(uint16_t class) {
322345fd 776
2d4c5cbc 777 switch (class) {
322345fd 778
2d4c5cbc
LP
779 case DNS_CLASS_IN:
780 return "IN";
322345fd 781
2d4c5cbc
LP
782 case DNS_CLASS_ANY:
783 return "ANY";
784 }
322345fd 785
2d4c5cbc
LP
786 return NULL;
787}
322345fd 788
2d4c5cbc
LP
789int dns_class_from_string(const char *s, uint16_t *class) {
790 assert(s);
791 assert(class);
792
793 if (strcaseeq(s, "IN"))
794 *class = DNS_CLASS_IN;
795 else if (strcaseeq(s, "ANY"))
796 *class = DNS_TYPE_ANY;
797 else
798 return -EINVAL;
322345fd 799
2d4c5cbc
LP
800 return 0;
801}