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