]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-rr.c
sd-bus: fix gvariant structure encoding
[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
5d45a880
TG
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
0dae31d4 302 case DNS_TYPE_LOC:
9de3e329
ZJS
303 case DNS_TYPE_A:
304 case DNS_TYPE_AAAA:
305 break;
9c92ce6d 306
9de3e329 307 default:
faa133f3 308 free(rr->generic.data);
9de3e329 309 }
322345fd 310
faa133f3
LP
311 dns_resource_key_unref(rr->key);
312 }
322345fd 313
faa133f3 314 free(rr);
322345fd 315
322345fd
LP
316 return NULL;
317}
318
623a4c97
LP
319int 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
322345fd
LP
353int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
354 int r;
355
356 assert(a);
357 assert(b);
358
faa133f3 359 r = dns_resource_key_equal(a->key, b->key);
322345fd
LP
360 if (r <= 0)
361 return r;
362
fd0b4602
LP
363 if (a->unparseable != b->unparseable)
364 return 0;
365
366 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
2d4c5cbc 367
9c92ce6d
LP
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
2d4c5cbc
LP
377 case DNS_TYPE_PTR:
378 case DNS_TYPE_NS:
379 case DNS_TYPE_CNAME:
8ac4e9e1 380 case DNS_TYPE_DNAME:
322345fd 381 return dns_name_equal(a->ptr.name, b->ptr.name);
2d4c5cbc
LP
382
383 case DNS_TYPE_HINFO:
384 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
385 strcaseeq(a->hinfo.os, b->hinfo.os);
386
9de3e329 387 case DNS_TYPE_SPF: /* exactly the same as TXT */
0f84a72e
DH
388 case DNS_TYPE_TXT:
389 return strv_equal(a->txt.strings, b->txt.strings);
2e276efc 390
2d4c5cbc 391 case DNS_TYPE_A:
322345fd 392 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
2d4c5cbc
LP
393
394 case DNS_TYPE_AAAA:
322345fd 395 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
2d4c5cbc
LP
396
397 case DNS_TYPE_SOA:
7e8e0422
LP
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;
9c92ce6d 410
946c7094
ZJS
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
0dae31d4
ZJS
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
abf126a3
TG
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
42cc2eeb
LP
434 case DNS_TYPE_SSHFP:
435 return a->sshfp.algorithm == b->sshfp.algorithm &&
436 a->sshfp.fptype == b->sshfp.fptype &&
437 a->sshfp.key_size == b->sshfp.key_size &&
438 memcmp(a->sshfp.key, b->sshfp.key, a->sshfp.key_size) == 0;
439
8db0d2f5
ZJS
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
151226ab
ZJS
447 case DNS_TYPE_RRSIG:
448 /* do the fast comparisons first */
03664a62
LN
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 ||
151226ab
ZJS
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
50f1e641
TG
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
5d45a880
TG
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
2d4c5cbc 475 default:
322345fd
LP
476 return a->generic.size == b->generic.size &&
477 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
2d4c5cbc 478 }
322345fd
LP
479}
480
0dae31d4
ZJS
481static 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
7c6423e1
TG
512static 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
50f1e641
TG
527static char *format_types(Bitmap *types) {
528 _cleanup_strv_free_ char **strv = NULL;
529 _cleanup_free_ char *str = NULL;
530 unsigned type;
531 int r;
532
533 BITMAP_FOREACH(type, types) {
534 if (dns_type_to_string(type)) {
535 r = strv_extend(&strv, strdup(dns_type_to_string(type)));
536 if (r < 0)
537 return NULL;
538 } else {
539 char *t;
540
541 r = asprintf(&t, "TYPE%u", type);
542 if (r < 0)
543 return NULL;
544
545 r = strv_extend(&strv, t);
546 if (r < 0)
547 return NULL;
548 }
549 }
550
551 str = strv_join(strv, " ");
552 if (!str)
553 return NULL;
554
555 return strjoin("( ", str, " )", NULL);
556}
557
2d4c5cbc 558int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
8db0d2f5 559 _cleanup_free_ char *k = NULL, *t = NULL;
2d4c5cbc
LP
560 char *s;
561 int r;
322345fd 562
2d4c5cbc 563 assert(rr);
322345fd 564
2d4c5cbc
LP
565 r = dns_resource_key_to_string(rr->key, &k);
566 if (r < 0)
567 return r;
322345fd 568
0dae31d4 569 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
322345fd 570
9c92ce6d
LP
571 case DNS_TYPE_SRV:
572 r = asprintf(&s, "%s %u %u %u %s",
573 k,
574 rr->srv.priority,
575 rr->srv.weight,
576 rr->srv.port,
577 strna(rr->srv.name));
578 if (r < 0)
579 return -ENOMEM;
580 break;
581
2d4c5cbc
LP
582 case DNS_TYPE_PTR:
583 case DNS_TYPE_NS:
584 case DNS_TYPE_CNAME:
8ac4e9e1 585 case DNS_TYPE_DNAME:
2d4c5cbc
LP
586 s = strjoin(k, " ", rr->ptr.name, NULL);
587 if (!s)
588 return -ENOMEM;
322345fd 589
2d4c5cbc 590 break;
322345fd 591
2d4c5cbc
LP
592 case DNS_TYPE_HINFO:
593 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
594 if (!s)
595 return -ENOMEM;
596 break;
322345fd 597
9de3e329 598 case DNS_TYPE_SPF: /* exactly the same as TXT */
8db0d2f5 599 case DNS_TYPE_TXT:
2e276efc
ZJS
600 t = strv_join_quoted(rr->txt.strings);
601 if (!t)
602 return -ENOMEM;
603
604 s = strjoin(k, " ", t, NULL);
605 if (!s)
606 return -ENOMEM;
607
608 break;
2e276efc 609
2d4c5cbc
LP
610 case DNS_TYPE_A: {
611 _cleanup_free_ char *x = NULL;
322345fd 612
2d4c5cbc
LP
613 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
614 if (r < 0)
615 return r;
322345fd 616
2d4c5cbc
LP
617 s = strjoin(k, " ", x, NULL);
618 if (!s)
619 return -ENOMEM;
620 break;
621 }
322345fd 622
8db0d2f5
ZJS
623 case DNS_TYPE_AAAA:
624 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
2d4c5cbc
LP
625 if (r < 0)
626 return r;
322345fd 627
8db0d2f5 628 s = strjoin(k, " ", t, NULL);
2d4c5cbc
LP
629 if (!s)
630 return -ENOMEM;
631 break;
322345fd 632
2d4c5cbc
LP
633 case DNS_TYPE_SOA:
634 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
635 k,
636 strna(rr->soa.mname),
637 strna(rr->soa.rname),
638 rr->soa.serial,
639 rr->soa.refresh,
640 rr->soa.retry,
641 rr->soa.expire,
642 rr->soa.minimum);
643 if (r < 0)
644 return -ENOMEM;
645 break;
646
946c7094
ZJS
647 case DNS_TYPE_MX:
648 r = asprintf(&s, "%s %u %s",
649 k,
650 rr->mx.priority,
651 rr->mx.exchange);
652 if (r < 0)
653 return -ENOMEM;
654 break;
655
8db0d2f5 656 case DNS_TYPE_LOC:
0dae31d4
ZJS
657 assert(rr->loc.version == 0);
658
8db0d2f5
ZJS
659 t = format_location(rr->loc.latitude,
660 rr->loc.longitude,
661 rr->loc.altitude,
662 rr->loc.size,
663 rr->loc.horiz_pre,
664 rr->loc.vert_pre);
665 if (!t)
0dae31d4
ZJS
666 return -ENOMEM;
667
8db0d2f5 668 s = strjoin(k, " ", t, NULL);
0dae31d4
ZJS
669 if (!s)
670 return -ENOMEM;
0dae31d4 671 break;
0dae31d4 672
abf126a3
TG
673 case DNS_TYPE_DS:
674 t = hexmem(rr->ds.digest, rr->ds.digest_size);
675 if (!t)
676 return -ENOMEM;
677
678 r = asprintf(&s, "%s %u %u %u %s",
679 k,
680 rr->ds.key_tag,
681 rr->ds.algorithm,
682 rr->ds.digest_type,
683 t);
684 if (r < 0)
685 return -ENOMEM;
686 break;
687
8db0d2f5
ZJS
688 case DNS_TYPE_SSHFP:
689 t = hexmem(rr->sshfp.key, rr->sshfp.key_size);
690 if (!t)
42cc2eeb
LP
691 return -ENOMEM;
692
693 r = asprintf(&s, "%s %u %u %s",
694 k,
695 rr->sshfp.algorithm,
696 rr->sshfp.fptype,
8db0d2f5 697 t);
42cc2eeb
LP
698 if (r < 0)
699 return -ENOMEM;
700 break;
42cc2eeb 701
ff3d6560
ZJS
702 case DNS_TYPE_DNSKEY: {
703 const char *alg;
704
705 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
706
1bf968f3 707 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
8db0d2f5
ZJS
708 if (!t)
709 return -ENOMEM;
2d4c5cbc 710
ff3d6560 711 r = asprintf(&s, "%s %u 3 %.*s%.*u %s",
8db0d2f5
ZJS
712 k,
713 dnskey_to_flags(rr),
ff3d6560
ZJS
714 alg ? -1 : 0, alg,
715 alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
8db0d2f5
ZJS
716 t);
717 if (r < 0)
2d4c5cbc 718 return -ENOMEM;
8db0d2f5 719 break;
ff3d6560 720 }
2d4c5cbc 721
151226ab
ZJS
722 case DNS_TYPE_RRSIG: {
723 const char *type, *alg;
7c6423e1 724 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
151226ab
ZJS
725
726 type = dns_type_to_string(rr->rrsig.type_covered);
727 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
728
1bf968f3 729 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
151226ab
ZJS
730 if (!t)
731 return -ENOMEM;
732
7c6423e1
TG
733 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
734 if (r < 0)
735 return r;
736
737 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
738 if (r < 0)
739 return r;
740
151226ab
ZJS
741 /* TYPE?? follows
742 * http://tools.ietf.org/html/rfc3597#section-5 */
743
7c6423e1 744 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
151226ab
ZJS
745 k,
746 type ?: "TYPE",
747 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
748 alg ? -1 : 0, alg,
749 alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
750 rr->rrsig.labels,
751 rr->rrsig.original_ttl,
7c6423e1
TG
752 expiration,
753 inception,
151226ab
ZJS
754 rr->rrsig.key_tag,
755 rr->rrsig.signer,
756 t);
757 if (r < 0)
758 return -ENOMEM;
759 break;
760 }
761
50f1e641
TG
762 case DNS_TYPE_NSEC:
763 t = format_types(rr->nsec.types);
764 if (!t)
765 return -ENOMEM;
766
767 r = asprintf(&s, "%s %s %s",
768 k,
769 rr->nsec.next_domain_name,
770 t);
771 if (r < 0)
772 return -ENOMEM;
773 break;
774
5d45a880
TG
775 case DNS_TYPE_NSEC3: {
776 _cleanup_free_ char *salt = NULL, *hash = NULL;
777
778 if (rr->nsec3.salt_size) {
779 salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
780 if (!salt)
781 return -ENOMEM;
782 }
783
784 hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
785 if (!hash)
786 return -ENOMEM;
787
788 t = format_types(rr->nsec3.types);
789 if (!t)
790 return -ENOMEM;
791
792 r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
793 k,
794 rr->nsec3.algorithm,
795 rr->nsec3.flags,
796 rr->nsec3.iterations,
797 rr->nsec3.salt_size ? salt : "-",
798 hash,
799 t);
800 if (r < 0)
801 return -ENOMEM;
802
803 break;
804 }
805
8db0d2f5
ZJS
806 default:
807 t = hexmem(rr->generic.data, rr->generic.size);
808 if (!t)
809 return -ENOMEM;
810
d23a27a9
TG
811 r = asprintf(&s, "%s \\# %"PRIu8" %s", k, rr->generic.size, t);
812 if (r < 0)
2d4c5cbc
LP
813 return -ENOMEM;
814 break;
8db0d2f5 815 }
2d4c5cbc
LP
816
817 *ret = s;
818 return 0;
819}
322345fd 820
2d4c5cbc 821const char *dns_class_to_string(uint16_t class) {
322345fd 822
2d4c5cbc 823 switch (class) {
322345fd 824
2d4c5cbc
LP
825 case DNS_CLASS_IN:
826 return "IN";
322345fd 827
2d4c5cbc
LP
828 case DNS_CLASS_ANY:
829 return "ANY";
830 }
322345fd 831
2d4c5cbc
LP
832 return NULL;
833}
322345fd 834
2d4c5cbc
LP
835int dns_class_from_string(const char *s, uint16_t *class) {
836 assert(s);
837 assert(class);
838
839 if (strcaseeq(s, "IN"))
840 *class = DNS_CLASS_IN;
841 else if (strcaseeq(s, "ANY"))
842 *class = DNS_TYPE_ANY;
843 else
844 return -EINVAL;
322345fd 845
2d4c5cbc
LP
846 return 0;
847}