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