basic: add a Bitmap implementation
[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
0dae31d4 291 case DNS_TYPE_LOC:
9de3e329
ZJS
292 case DNS_TYPE_A:
293 case DNS_TYPE_AAAA:
294 break;
9c92ce6d 295
9de3e329 296 default:
faa133f3 297 free(rr->generic.data);
9de3e329 298 }
322345fd 299
faa133f3
LP
300 dns_resource_key_unref(rr->key);
301 }
322345fd 302
faa133f3 303 free(rr);
322345fd 304
322345fd
LP
305 return NULL;
306}
307
623a4c97
LP
308int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
309 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
310 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
311 _cleanup_free_ char *ptr = NULL;
312 int r;
313
314 assert(ret);
315 assert(address);
316 assert(hostname);
317
318 r = dns_name_reverse(family, address, &ptr);
319 if (r < 0)
320 return r;
321
322 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
323 if (!key)
324 return -ENOMEM;
325
326 ptr = NULL;
327
328 rr = dns_resource_record_new(key);
329 if (!rr)
330 return -ENOMEM;
331
332 rr->ptr.name = strdup(hostname);
333 if (!rr->ptr.name)
334 return -ENOMEM;
335
336 *ret = rr;
337 rr = NULL;
338
339 return 0;
340}
341
322345fd
LP
342int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
343 int r;
344
345 assert(a);
346 assert(b);
347
faa133f3 348 r = dns_resource_key_equal(a->key, b->key);
322345fd
LP
349 if (r <= 0)
350 return r;
351
fd0b4602
LP
352 if (a->unparseable != b->unparseable)
353 return 0;
354
355 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
2d4c5cbc 356
9c92ce6d
LP
357 case DNS_TYPE_SRV:
358 r = dns_name_equal(a->srv.name, b->srv.name);
359 if (r <= 0)
360 return r;
361
362 return a->srv.priority == b->srv.priority &&
363 a->srv.weight == b->srv.weight &&
364 a->srv.port == b->srv.port;
365
2d4c5cbc
LP
366 case DNS_TYPE_PTR:
367 case DNS_TYPE_NS:
368 case DNS_TYPE_CNAME:
8ac4e9e1 369 case DNS_TYPE_DNAME:
322345fd 370 return dns_name_equal(a->ptr.name, b->ptr.name);
2d4c5cbc
LP
371
372 case DNS_TYPE_HINFO:
373 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
374 strcaseeq(a->hinfo.os, b->hinfo.os);
375
9de3e329 376 case DNS_TYPE_SPF: /* exactly the same as TXT */
0f84a72e
DH
377 case DNS_TYPE_TXT:
378 return strv_equal(a->txt.strings, b->txt.strings);
2e276efc 379
2d4c5cbc 380 case DNS_TYPE_A:
322345fd 381 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
2d4c5cbc
LP
382
383 case DNS_TYPE_AAAA:
322345fd 384 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
2d4c5cbc
LP
385
386 case DNS_TYPE_SOA:
7e8e0422
LP
387 r = dns_name_equal(a->soa.mname, b->soa.mname);
388 if (r <= 0)
389 return r;
390 r = dns_name_equal(a->soa.rname, b->soa.rname);
391 if (r <= 0)
392 return r;
393
394 return a->soa.serial == b->soa.serial &&
395 a->soa.refresh == b->soa.refresh &&
396 a->soa.retry == b->soa.retry &&
397 a->soa.expire == b->soa.expire &&
398 a->soa.minimum == b->soa.minimum;
9c92ce6d 399
946c7094
ZJS
400 case DNS_TYPE_MX:
401 if (a->mx.priority != b->mx.priority)
402 return 0;
403
404 return dns_name_equal(a->mx.exchange, b->mx.exchange);
405
0dae31d4
ZJS
406 case DNS_TYPE_LOC:
407 assert(a->loc.version == b->loc.version);
408
409 return a->loc.size == b->loc.size &&
410 a->loc.horiz_pre == b->loc.horiz_pre &&
411 a->loc.vert_pre == b->loc.vert_pre &&
412 a->loc.latitude == b->loc.latitude &&
413 a->loc.longitude == b->loc.longitude &&
414 a->loc.altitude == b->loc.altitude;
415
abf126a3
TG
416 case DNS_TYPE_DS:
417 return a->ds.key_tag == b->ds.key_tag &&
418 a->ds.algorithm == b->ds.algorithm &&
419 a->ds.digest_type == b->ds.digest_type &&
420 a->ds.digest_size == b->ds.digest_size &&
421 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
422
42cc2eeb
LP
423 case DNS_TYPE_SSHFP:
424 return a->sshfp.algorithm == b->sshfp.algorithm &&
425 a->sshfp.fptype == b->sshfp.fptype &&
426 a->sshfp.key_size == b->sshfp.key_size &&
427 memcmp(a->sshfp.key, b->sshfp.key, a->sshfp.key_size) == 0;
428
8db0d2f5
ZJS
429 case DNS_TYPE_DNSKEY:
430 return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag &&
431 a->dnskey.sep_flag == b->dnskey.sep_flag &&
432 a->dnskey.algorithm == b->dnskey.algorithm &&
433 a->dnskey.key_size == b->dnskey.key_size &&
434 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
435
151226ab
ZJS
436 case DNS_TYPE_RRSIG:
437 /* do the fast comparisons first */
03664a62
LN
438 if (a->rrsig.type_covered != b->rrsig.type_covered ||
439 a->rrsig.algorithm != b->rrsig.algorithm ||
440 a->rrsig.labels != b->rrsig.labels ||
441 a->rrsig.original_ttl != b->rrsig.original_ttl ||
442 a->rrsig.expiration != b->rrsig.expiration ||
443 a->rrsig.inception != b->rrsig.inception ||
444 a->rrsig.key_tag != b->rrsig.key_tag ||
151226ab
ZJS
445 a->rrsig.signature_size != b->rrsig.signature_size ||
446 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
447 return false;
448
449 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
450
2d4c5cbc 451 default:
322345fd
LP
452 return a->generic.size == b->generic.size &&
453 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
2d4c5cbc 454 }
322345fd
LP
455}
456
0dae31d4
ZJS
457static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
458 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
459 char *s;
460 char NS = latitude >= 1U<<31 ? 'N' : 'S';
461 char EW = longitude >= 1U<<31 ? 'E' : 'W';
462
463 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
464 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
465 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
466 double siz = (size >> 4) * exp10((double) (size & 0xF));
467 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
468 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
469
470 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
471 (lat / 60000 / 60),
472 (lat / 60000) % 60,
473 (lat % 60000) / 1000.,
474 NS,
475 (lon / 60000 / 60),
476 (lon / 60000) % 60,
477 (lon % 60000) / 1000.,
478 EW,
479 alt / 100.,
480 siz / 100.,
481 hor / 100.,
482 ver / 100.) < 0)
483 return NULL;
484
485 return s;
486}
487
7c6423e1
TG
488static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
489 struct tm tm;
490
491 assert(buf);
492 assert(l > strlen("YYYYMMDDHHmmSS"));
493
494 if (!gmtime_r(&sec, &tm))
495 return -EINVAL;
496
497 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
498 return -EINVAL;
499
500 return 0;
501}
502
2d4c5cbc 503int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
8db0d2f5 504 _cleanup_free_ char *k = NULL, *t = NULL;
2d4c5cbc
LP
505 char *s;
506 int r;
322345fd 507
2d4c5cbc 508 assert(rr);
322345fd 509
2d4c5cbc
LP
510 r = dns_resource_key_to_string(rr->key, &k);
511 if (r < 0)
512 return r;
322345fd 513
0dae31d4 514 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
322345fd 515
9c92ce6d
LP
516 case DNS_TYPE_SRV:
517 r = asprintf(&s, "%s %u %u %u %s",
518 k,
519 rr->srv.priority,
520 rr->srv.weight,
521 rr->srv.port,
522 strna(rr->srv.name));
523 if (r < 0)
524 return -ENOMEM;
525 break;
526
2d4c5cbc
LP
527 case DNS_TYPE_PTR:
528 case DNS_TYPE_NS:
529 case DNS_TYPE_CNAME:
8ac4e9e1 530 case DNS_TYPE_DNAME:
2d4c5cbc
LP
531 s = strjoin(k, " ", rr->ptr.name, NULL);
532 if (!s)
533 return -ENOMEM;
322345fd 534
2d4c5cbc 535 break;
322345fd 536
2d4c5cbc
LP
537 case DNS_TYPE_HINFO:
538 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
539 if (!s)
540 return -ENOMEM;
541 break;
322345fd 542
9de3e329 543 case DNS_TYPE_SPF: /* exactly the same as TXT */
8db0d2f5 544 case DNS_TYPE_TXT:
2e276efc
ZJS
545 t = strv_join_quoted(rr->txt.strings);
546 if (!t)
547 return -ENOMEM;
548
549 s = strjoin(k, " ", t, NULL);
550 if (!s)
551 return -ENOMEM;
552
553 break;
2e276efc 554
2d4c5cbc
LP
555 case DNS_TYPE_A: {
556 _cleanup_free_ char *x = NULL;
322345fd 557
2d4c5cbc
LP
558 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
559 if (r < 0)
560 return r;
322345fd 561
2d4c5cbc
LP
562 s = strjoin(k, " ", x, NULL);
563 if (!s)
564 return -ENOMEM;
565 break;
566 }
322345fd 567
8db0d2f5
ZJS
568 case DNS_TYPE_AAAA:
569 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
2d4c5cbc
LP
570 if (r < 0)
571 return r;
322345fd 572
8db0d2f5 573 s = strjoin(k, " ", t, NULL);
2d4c5cbc
LP
574 if (!s)
575 return -ENOMEM;
576 break;
322345fd 577
2d4c5cbc
LP
578 case DNS_TYPE_SOA:
579 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
580 k,
581 strna(rr->soa.mname),
582 strna(rr->soa.rname),
583 rr->soa.serial,
584 rr->soa.refresh,
585 rr->soa.retry,
586 rr->soa.expire,
587 rr->soa.minimum);
588 if (r < 0)
589 return -ENOMEM;
590 break;
591
946c7094
ZJS
592 case DNS_TYPE_MX:
593 r = asprintf(&s, "%s %u %s",
594 k,
595 rr->mx.priority,
596 rr->mx.exchange);
597 if (r < 0)
598 return -ENOMEM;
599 break;
600
8db0d2f5 601 case DNS_TYPE_LOC:
0dae31d4
ZJS
602 assert(rr->loc.version == 0);
603
8db0d2f5
ZJS
604 t = format_location(rr->loc.latitude,
605 rr->loc.longitude,
606 rr->loc.altitude,
607 rr->loc.size,
608 rr->loc.horiz_pre,
609 rr->loc.vert_pre);
610 if (!t)
0dae31d4
ZJS
611 return -ENOMEM;
612
8db0d2f5 613 s = strjoin(k, " ", t, NULL);
0dae31d4
ZJS
614 if (!s)
615 return -ENOMEM;
0dae31d4 616 break;
0dae31d4 617
abf126a3
TG
618 case DNS_TYPE_DS:
619 t = hexmem(rr->ds.digest, rr->ds.digest_size);
620 if (!t)
621 return -ENOMEM;
622
623 r = asprintf(&s, "%s %u %u %u %s",
624 k,
625 rr->ds.key_tag,
626 rr->ds.algorithm,
627 rr->ds.digest_type,
628 t);
629 if (r < 0)
630 return -ENOMEM;
631 break;
632
8db0d2f5
ZJS
633 case DNS_TYPE_SSHFP:
634 t = hexmem(rr->sshfp.key, rr->sshfp.key_size);
635 if (!t)
42cc2eeb
LP
636 return -ENOMEM;
637
638 r = asprintf(&s, "%s %u %u %s",
639 k,
640 rr->sshfp.algorithm,
641 rr->sshfp.fptype,
8db0d2f5 642 t);
42cc2eeb
LP
643 if (r < 0)
644 return -ENOMEM;
645 break;
42cc2eeb 646
ff3d6560
ZJS
647 case DNS_TYPE_DNSKEY: {
648 const char *alg;
649
650 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
651
1bf968f3 652 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
8db0d2f5
ZJS
653 if (!t)
654 return -ENOMEM;
2d4c5cbc 655
ff3d6560 656 r = asprintf(&s, "%s %u 3 %.*s%.*u %s",
8db0d2f5
ZJS
657 k,
658 dnskey_to_flags(rr),
ff3d6560
ZJS
659 alg ? -1 : 0, alg,
660 alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
8db0d2f5
ZJS
661 t);
662 if (r < 0)
2d4c5cbc 663 return -ENOMEM;
8db0d2f5 664 break;
ff3d6560 665 }
2d4c5cbc 666
151226ab
ZJS
667 case DNS_TYPE_RRSIG: {
668 const char *type, *alg;
7c6423e1 669 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
151226ab
ZJS
670
671 type = dns_type_to_string(rr->rrsig.type_covered);
672 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
673
1bf968f3 674 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
151226ab
ZJS
675 if (!t)
676 return -ENOMEM;
677
7c6423e1
TG
678 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
679 if (r < 0)
680 return r;
681
682 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
683 if (r < 0)
684 return r;
685
151226ab
ZJS
686 /* TYPE?? follows
687 * http://tools.ietf.org/html/rfc3597#section-5 */
688
7c6423e1 689 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
151226ab
ZJS
690 k,
691 type ?: "TYPE",
692 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
693 alg ? -1 : 0, alg,
694 alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
695 rr->rrsig.labels,
696 rr->rrsig.original_ttl,
7c6423e1
TG
697 expiration,
698 inception,
151226ab
ZJS
699 rr->rrsig.key_tag,
700 rr->rrsig.signer,
701 t);
702 if (r < 0)
703 return -ENOMEM;
704 break;
705 }
706
8db0d2f5
ZJS
707 default:
708 t = hexmem(rr->generic.data, rr->generic.size);
709 if (!t)
710 return -ENOMEM;
711
d23a27a9
TG
712 r = asprintf(&s, "%s \\# %"PRIu8" %s", k, rr->generic.size, t);
713 if (r < 0)
2d4c5cbc
LP
714 return -ENOMEM;
715 break;
8db0d2f5 716 }
2d4c5cbc
LP
717
718 *ret = s;
719 return 0;
720}
322345fd 721
2d4c5cbc 722const char *dns_class_to_string(uint16_t class) {
322345fd 723
2d4c5cbc 724 switch (class) {
322345fd 725
2d4c5cbc
LP
726 case DNS_CLASS_IN:
727 return "IN";
322345fd 728
2d4c5cbc
LP
729 case DNS_CLASS_ANY:
730 return "ANY";
731 }
322345fd 732
2d4c5cbc
LP
733 return NULL;
734}
322345fd 735
2d4c5cbc
LP
736int dns_class_from_string(const char *s, uint16_t *class) {
737 assert(s);
738 assert(class);
739
740 if (strcaseeq(s, "IN"))
741 *class = DNS_CLASS_IN;
742 else if (strcaseeq(s, "ANY"))
743 *class = DNS_TYPE_ANY;
744 else
745 return -EINVAL;
322345fd 746
2d4c5cbc
LP
747 return 0;
748}