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