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