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