]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-rr.c
hwdb: Update database of Bluetooth company identifiers
[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 278 case DNS_TYPE_SSHFP:
549c1a25 279 free(rr->sshfp.fingerprint);
42cc2eeb
LP
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
78c6a153
LP
353int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
354 DnsResourceRecord *rr;
355
356 assert(ret);
357 assert(address);
358 assert(family);
359
360 if (family == AF_INET) {
361
362 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
363 if (!rr)
364 return -ENOMEM;
365
366 rr->a.in_addr = address->in;
367
368 } else if (family == AF_INET6) {
369
370 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
371 if (!rr)
372 return -ENOMEM;
373
374 rr->aaaa.in6_addr = address->in6;
375 } else
376 return -EAFNOSUPPORT;
377
378 *ret = rr;
379
380 return 0;
381}
382
322345fd
LP
383int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
384 int r;
385
386 assert(a);
387 assert(b);
388
faa133f3 389 r = dns_resource_key_equal(a->key, b->key);
322345fd
LP
390 if (r <= 0)
391 return r;
392
fd0b4602
LP
393 if (a->unparseable != b->unparseable)
394 return 0;
395
396 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
2d4c5cbc 397
9c92ce6d
LP
398 case DNS_TYPE_SRV:
399 r = dns_name_equal(a->srv.name, b->srv.name);
400 if (r <= 0)
401 return r;
402
403 return a->srv.priority == b->srv.priority &&
404 a->srv.weight == b->srv.weight &&
405 a->srv.port == b->srv.port;
406
2d4c5cbc
LP
407 case DNS_TYPE_PTR:
408 case DNS_TYPE_NS:
409 case DNS_TYPE_CNAME:
8ac4e9e1 410 case DNS_TYPE_DNAME:
322345fd 411 return dns_name_equal(a->ptr.name, b->ptr.name);
2d4c5cbc
LP
412
413 case DNS_TYPE_HINFO:
414 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
415 strcaseeq(a->hinfo.os, b->hinfo.os);
416
9de3e329 417 case DNS_TYPE_SPF: /* exactly the same as TXT */
0f84a72e
DH
418 case DNS_TYPE_TXT:
419 return strv_equal(a->txt.strings, b->txt.strings);
2e276efc 420
2d4c5cbc 421 case DNS_TYPE_A:
322345fd 422 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
2d4c5cbc
LP
423
424 case DNS_TYPE_AAAA:
322345fd 425 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
2d4c5cbc
LP
426
427 case DNS_TYPE_SOA:
7e8e0422
LP
428 r = dns_name_equal(a->soa.mname, b->soa.mname);
429 if (r <= 0)
430 return r;
431 r = dns_name_equal(a->soa.rname, b->soa.rname);
432 if (r <= 0)
433 return r;
434
435 return a->soa.serial == b->soa.serial &&
436 a->soa.refresh == b->soa.refresh &&
437 a->soa.retry == b->soa.retry &&
438 a->soa.expire == b->soa.expire &&
439 a->soa.minimum == b->soa.minimum;
9c92ce6d 440
946c7094
ZJS
441 case DNS_TYPE_MX:
442 if (a->mx.priority != b->mx.priority)
443 return 0;
444
445 return dns_name_equal(a->mx.exchange, b->mx.exchange);
446
0dae31d4
ZJS
447 case DNS_TYPE_LOC:
448 assert(a->loc.version == b->loc.version);
449
450 return a->loc.size == b->loc.size &&
451 a->loc.horiz_pre == b->loc.horiz_pre &&
452 a->loc.vert_pre == b->loc.vert_pre &&
453 a->loc.latitude == b->loc.latitude &&
454 a->loc.longitude == b->loc.longitude &&
455 a->loc.altitude == b->loc.altitude;
456
abf126a3
TG
457 case DNS_TYPE_DS:
458 return a->ds.key_tag == b->ds.key_tag &&
459 a->ds.algorithm == b->ds.algorithm &&
460 a->ds.digest_type == b->ds.digest_type &&
461 a->ds.digest_size == b->ds.digest_size &&
462 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
463
42cc2eeb
LP
464 case DNS_TYPE_SSHFP:
465 return a->sshfp.algorithm == b->sshfp.algorithm &&
466 a->sshfp.fptype == b->sshfp.fptype &&
549c1a25
TG
467 a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
468 memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
42cc2eeb 469
8db0d2f5
ZJS
470 case DNS_TYPE_DNSKEY:
471 return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag &&
472 a->dnskey.sep_flag == b->dnskey.sep_flag &&
473 a->dnskey.algorithm == b->dnskey.algorithm &&
474 a->dnskey.key_size == b->dnskey.key_size &&
475 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
476
151226ab
ZJS
477 case DNS_TYPE_RRSIG:
478 /* do the fast comparisons first */
03664a62
LN
479 if (a->rrsig.type_covered != b->rrsig.type_covered ||
480 a->rrsig.algorithm != b->rrsig.algorithm ||
481 a->rrsig.labels != b->rrsig.labels ||
482 a->rrsig.original_ttl != b->rrsig.original_ttl ||
483 a->rrsig.expiration != b->rrsig.expiration ||
484 a->rrsig.inception != b->rrsig.inception ||
485 a->rrsig.key_tag != b->rrsig.key_tag ||
151226ab
ZJS
486 a->rrsig.signature_size != b->rrsig.signature_size ||
487 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
488 return false;
489
490 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
491
50f1e641
TG
492 case DNS_TYPE_NSEC:
493 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
494 bitmap_equal(a->nsec.types, b->nsec.types);
495
5d45a880
TG
496 case DNS_TYPE_NSEC3:
497 return a->nsec3.algorithm == b->nsec3.algorithm &&
498 a->nsec3.flags == b->nsec3.flags &&
499 a->nsec3.iterations == b->nsec3.iterations &&
500 a->nsec3.salt_size == b->nsec3.salt_size &&
501 memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
502 memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
503 bitmap_equal(a->nsec3.types, b->nsec3.types);
504
2d4c5cbc 505 default:
322345fd
LP
506 return a->generic.size == b->generic.size &&
507 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
2d4c5cbc 508 }
322345fd
LP
509}
510
0dae31d4
ZJS
511static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
512 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
513 char *s;
514 char NS = latitude >= 1U<<31 ? 'N' : 'S';
515 char EW = longitude >= 1U<<31 ? 'E' : 'W';
516
517 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
518 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
519 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
520 double siz = (size >> 4) * exp10((double) (size & 0xF));
521 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
522 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
523
524 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
525 (lat / 60000 / 60),
526 (lat / 60000) % 60,
527 (lat % 60000) / 1000.,
528 NS,
529 (lon / 60000 / 60),
530 (lon / 60000) % 60,
531 (lon % 60000) / 1000.,
532 EW,
533 alt / 100.,
534 siz / 100.,
535 hor / 100.,
536 ver / 100.) < 0)
537 return NULL;
538
539 return s;
540}
541
7c6423e1
TG
542static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
543 struct tm tm;
544
545 assert(buf);
546 assert(l > strlen("YYYYMMDDHHmmSS"));
547
548 if (!gmtime_r(&sec, &tm))
549 return -EINVAL;
550
551 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
552 return -EINVAL;
553
554 return 0;
555}
556
50f1e641
TG
557static char *format_types(Bitmap *types) {
558 _cleanup_strv_free_ char **strv = NULL;
559 _cleanup_free_ char *str = NULL;
cb57dd41 560 Iterator i;
50f1e641
TG
561 unsigned type;
562 int r;
563
cb57dd41 564 BITMAP_FOREACH(type, types, i) {
50f1e641 565 if (dns_type_to_string(type)) {
2c1fb4f7 566 r = strv_extend(&strv, dns_type_to_string(type));
50f1e641
TG
567 if (r < 0)
568 return NULL;
569 } else {
570 char *t;
571
572 r = asprintf(&t, "TYPE%u", type);
573 if (r < 0)
574 return NULL;
575
2c1fb4f7 576 r = strv_consume(&strv, t);
50f1e641
TG
577 if (r < 0)
578 return NULL;
579 }
580 }
581
582 str = strv_join(strv, " ");
583 if (!str)
584 return NULL;
585
586 return strjoin("( ", str, " )", NULL);
587}
588
2d4c5cbc 589int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
8db0d2f5 590 _cleanup_free_ char *k = NULL, *t = NULL;
2d4c5cbc
LP
591 char *s;
592 int r;
322345fd 593
2d4c5cbc 594 assert(rr);
322345fd 595
2d4c5cbc
LP
596 r = dns_resource_key_to_string(rr->key, &k);
597 if (r < 0)
598 return r;
322345fd 599
0dae31d4 600 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
322345fd 601
9c92ce6d
LP
602 case DNS_TYPE_SRV:
603 r = asprintf(&s, "%s %u %u %u %s",
604 k,
605 rr->srv.priority,
606 rr->srv.weight,
607 rr->srv.port,
608 strna(rr->srv.name));
609 if (r < 0)
610 return -ENOMEM;
611 break;
612
2d4c5cbc
LP
613 case DNS_TYPE_PTR:
614 case DNS_TYPE_NS:
615 case DNS_TYPE_CNAME:
8ac4e9e1 616 case DNS_TYPE_DNAME:
2d4c5cbc
LP
617 s = strjoin(k, " ", rr->ptr.name, NULL);
618 if (!s)
619 return -ENOMEM;
322345fd 620
2d4c5cbc 621 break;
322345fd 622
2d4c5cbc
LP
623 case DNS_TYPE_HINFO:
624 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
625 if (!s)
626 return -ENOMEM;
627 break;
322345fd 628
9de3e329 629 case DNS_TYPE_SPF: /* exactly the same as TXT */
8db0d2f5 630 case DNS_TYPE_TXT:
2e276efc
ZJS
631 t = strv_join_quoted(rr->txt.strings);
632 if (!t)
633 return -ENOMEM;
634
635 s = strjoin(k, " ", t, NULL);
636 if (!s)
637 return -ENOMEM;
638
639 break;
2e276efc 640
2d4c5cbc
LP
641 case DNS_TYPE_A: {
642 _cleanup_free_ char *x = NULL;
322345fd 643
2d4c5cbc
LP
644 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
645 if (r < 0)
646 return r;
322345fd 647
2d4c5cbc
LP
648 s = strjoin(k, " ", x, NULL);
649 if (!s)
650 return -ENOMEM;
651 break;
652 }
322345fd 653
8db0d2f5
ZJS
654 case DNS_TYPE_AAAA:
655 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
2d4c5cbc
LP
656 if (r < 0)
657 return r;
322345fd 658
8db0d2f5 659 s = strjoin(k, " ", t, NULL);
2d4c5cbc
LP
660 if (!s)
661 return -ENOMEM;
662 break;
322345fd 663
2d4c5cbc
LP
664 case DNS_TYPE_SOA:
665 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
666 k,
667 strna(rr->soa.mname),
668 strna(rr->soa.rname),
669 rr->soa.serial,
670 rr->soa.refresh,
671 rr->soa.retry,
672 rr->soa.expire,
673 rr->soa.minimum);
674 if (r < 0)
675 return -ENOMEM;
676 break;
677
946c7094
ZJS
678 case DNS_TYPE_MX:
679 r = asprintf(&s, "%s %u %s",
680 k,
681 rr->mx.priority,
682 rr->mx.exchange);
683 if (r < 0)
684 return -ENOMEM;
685 break;
686
8db0d2f5 687 case DNS_TYPE_LOC:
0dae31d4
ZJS
688 assert(rr->loc.version == 0);
689
8db0d2f5
ZJS
690 t = format_location(rr->loc.latitude,
691 rr->loc.longitude,
692 rr->loc.altitude,
693 rr->loc.size,
694 rr->loc.horiz_pre,
695 rr->loc.vert_pre);
696 if (!t)
0dae31d4
ZJS
697 return -ENOMEM;
698
8db0d2f5 699 s = strjoin(k, " ", t, NULL);
0dae31d4
ZJS
700 if (!s)
701 return -ENOMEM;
0dae31d4 702 break;
0dae31d4 703
abf126a3
TG
704 case DNS_TYPE_DS:
705 t = hexmem(rr->ds.digest, rr->ds.digest_size);
706 if (!t)
707 return -ENOMEM;
708
709 r = asprintf(&s, "%s %u %u %u %s",
710 k,
711 rr->ds.key_tag,
712 rr->ds.algorithm,
713 rr->ds.digest_type,
714 t);
715 if (r < 0)
716 return -ENOMEM;
717 break;
718
8db0d2f5 719 case DNS_TYPE_SSHFP:
549c1a25 720 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
8db0d2f5 721 if (!t)
42cc2eeb
LP
722 return -ENOMEM;
723
724 r = asprintf(&s, "%s %u %u %s",
725 k,
726 rr->sshfp.algorithm,
727 rr->sshfp.fptype,
8db0d2f5 728 t);
42cc2eeb
LP
729 if (r < 0)
730 return -ENOMEM;
731 break;
42cc2eeb 732
ff3d6560
ZJS
733 case DNS_TYPE_DNSKEY: {
734 const char *alg;
735
736 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
737
1bf968f3 738 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
8db0d2f5
ZJS
739 if (!t)
740 return -ENOMEM;
2d4c5cbc 741
ff3d6560 742 r = asprintf(&s, "%s %u 3 %.*s%.*u %s",
8db0d2f5
ZJS
743 k,
744 dnskey_to_flags(rr),
ff3d6560
ZJS
745 alg ? -1 : 0, alg,
746 alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
8db0d2f5
ZJS
747 t);
748 if (r < 0)
2d4c5cbc 749 return -ENOMEM;
8db0d2f5 750 break;
ff3d6560 751 }
2d4c5cbc 752
151226ab
ZJS
753 case DNS_TYPE_RRSIG: {
754 const char *type, *alg;
7c6423e1 755 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
151226ab
ZJS
756
757 type = dns_type_to_string(rr->rrsig.type_covered);
758 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
759
1bf968f3 760 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
151226ab
ZJS
761 if (!t)
762 return -ENOMEM;
763
7c6423e1
TG
764 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
765 if (r < 0)
766 return r;
767
768 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
769 if (r < 0)
770 return r;
771
151226ab
ZJS
772 /* TYPE?? follows
773 * http://tools.ietf.org/html/rfc3597#section-5 */
774
7c6423e1 775 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
151226ab
ZJS
776 k,
777 type ?: "TYPE",
778 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
779 alg ? -1 : 0, alg,
780 alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
781 rr->rrsig.labels,
782 rr->rrsig.original_ttl,
7c6423e1
TG
783 expiration,
784 inception,
151226ab
ZJS
785 rr->rrsig.key_tag,
786 rr->rrsig.signer,
787 t);
788 if (r < 0)
789 return -ENOMEM;
790 break;
791 }
792
50f1e641
TG
793 case DNS_TYPE_NSEC:
794 t = format_types(rr->nsec.types);
795 if (!t)
796 return -ENOMEM;
797
798 r = asprintf(&s, "%s %s %s",
799 k,
800 rr->nsec.next_domain_name,
801 t);
802 if (r < 0)
803 return -ENOMEM;
804 break;
805
5d45a880
TG
806 case DNS_TYPE_NSEC3: {
807 _cleanup_free_ char *salt = NULL, *hash = NULL;
808
f5430a3e 809 if (rr->nsec3.salt_size > 0) {
5d45a880
TG
810 salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
811 if (!salt)
812 return -ENOMEM;
813 }
814
815 hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
816 if (!hash)
817 return -ENOMEM;
818
819 t = format_types(rr->nsec3.types);
820 if (!t)
821 return -ENOMEM;
822
823 r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
824 k,
825 rr->nsec3.algorithm,
826 rr->nsec3.flags,
827 rr->nsec3.iterations,
f5430a3e 828 rr->nsec3.salt_size > 0 ? salt : "-",
5d45a880
TG
829 hash,
830 t);
831 if (r < 0)
832 return -ENOMEM;
833
834 break;
835 }
836
8db0d2f5
ZJS
837 default:
838 t = hexmem(rr->generic.data, rr->generic.size);
839 if (!t)
840 return -ENOMEM;
841
f5430a3e 842 r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
d23a27a9 843 if (r < 0)
2d4c5cbc
LP
844 return -ENOMEM;
845 break;
8db0d2f5 846 }
2d4c5cbc
LP
847
848 *ret = s;
849 return 0;
850}
322345fd 851
2d4c5cbc 852const char *dns_class_to_string(uint16_t class) {
322345fd 853
2d4c5cbc 854 switch (class) {
322345fd 855
2d4c5cbc
LP
856 case DNS_CLASS_IN:
857 return "IN";
322345fd 858
2d4c5cbc
LP
859 case DNS_CLASS_ANY:
860 return "ANY";
861 }
322345fd 862
2d4c5cbc
LP
863 return NULL;
864}
322345fd 865
2d4c5cbc
LP
866int dns_class_from_string(const char *s, uint16_t *class) {
867 assert(s);
868 assert(class);
869
870 if (strcaseeq(s, "IN"))
871 *class = DNS_CLASS_IN;
872 else if (strcaseeq(s, "ANY"))
816b4547 873 *class = DNS_CLASS_ANY;
2d4c5cbc
LP
874 else
875 return -EINVAL;
322345fd 876
2d4c5cbc
LP
877 return 0;
878}