]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-rr.c
resolved: implement client-side DNAME resolution
[thirdparty/systemd.git] / src / resolve / resolved-dns-rr.c
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
22 #include <math.h>
23
24 #include "alloc-util.h"
25 #include "dns-domain.h"
26 #include "dns-type.h"
27 #include "hexdecoct.h"
28 #include "resolved-dns-packet.h"
29 #include "resolved-dns-rr.h"
30 #include "string-util.h"
31 #include "strv.h"
32
33 DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
34 DnsResourceKey *k;
35 size_t l;
36
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
53 DnsResourceKey* 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
59 DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) {
60 int r;
61
62 assert(key);
63 assert(cname);
64
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 }
87 }
88
89 DnsResourceKey* 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
106 DnsResourceKey* 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
117 DnsResourceKey* 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
132 int 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
148 int 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
161 int 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
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
173 return 0;
174 }
175
176 static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
177 const DnsResourceKey *k = i;
178
179 assert(k);
180
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);
184 }
185
186 static int dns_resource_key_compare_func(const void *a, const void *b) {
187 const DnsResourceKey *x = a, *y = b;
188 int ret;
189
190 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
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
207 const struct hash_ops dns_resource_key_hash_ops = {
208 .hash = dns_resource_key_hash_func,
209 .compare = dns_resource_key_compare_func
210 };
211
212 int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
213 char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
214 const char *c, *t;
215 char *s;
216
217 c = dns_class_to_string(key->class);
218 if (!c) {
219 sprintf(cbuf, "CLASS%u", key->class);
220 c = cbuf;
221 }
222
223 t = dns_type_to_string(key->type);
224 if (!t){
225 sprintf(tbuf, "TYPE%u", key->type);
226 t = tbuf;
227 }
228
229 if (asprintf(&s, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key), c, t) < 0)
230 return -ENOMEM;
231
232 *ret = s;
233 return 0;
234 }
235
236 DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
237 DnsResourceRecord *rr;
238
239 rr = new0(DnsResourceRecord, 1);
240 if (!rr)
241 return NULL;
242
243 rr->n_ref = 1;
244 rr->key = dns_resource_key_ref(key);
245
246 return rr;
247 }
248
249 DnsResourceRecord* 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
259 DnsResourceRecord* 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
269 DnsResourceRecord* 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
280 if (rr->key) {
281 switch(rr->key->type) {
282
283 case DNS_TYPE_SRV:
284 free(rr->srv.name);
285 break;
286
287 case DNS_TYPE_PTR:
288 case DNS_TYPE_NS:
289 case DNS_TYPE_CNAME:
290 case DNS_TYPE_DNAME:
291 free(rr->ptr.name);
292 break;
293
294 case DNS_TYPE_HINFO:
295 free(rr->hinfo.cpu);
296 free(rr->hinfo.os);
297 break;
298
299 case DNS_TYPE_TXT:
300 case DNS_TYPE_SPF:
301 dns_txt_item_free_all(rr->txt.items);
302 break;
303
304 case DNS_TYPE_SOA:
305 free(rr->soa.mname);
306 free(rr->soa.rname);
307 break;
308
309 case DNS_TYPE_MX:
310 free(rr->mx.exchange);
311 break;
312
313 case DNS_TYPE_DS:
314 free(rr->ds.digest);
315 break;
316
317 case DNS_TYPE_SSHFP:
318 free(rr->sshfp.fingerprint);
319 break;
320
321 case DNS_TYPE_DNSKEY:
322 free(rr->dnskey.key);
323 break;
324
325 case DNS_TYPE_RRSIG:
326 free(rr->rrsig.signer);
327 free(rr->rrsig.signature);
328 break;
329
330 case DNS_TYPE_NSEC:
331 free(rr->nsec.next_domain_name);
332 bitmap_free(rr->nsec.types);
333 break;
334
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
341 case DNS_TYPE_LOC:
342 case DNS_TYPE_A:
343 case DNS_TYPE_AAAA:
344 break;
345
346 default:
347 free(rr->generic.data);
348 }
349
350 dns_resource_key_unref(rr->key);
351 }
352
353 free(rr);
354
355 return NULL;
356 }
357
358 int 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
392 int 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
422 int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
423 int r;
424
425 assert(a);
426 assert(b);
427
428 r = dns_resource_key_equal(a->key, b->key);
429 if (r <= 0)
430 return r;
431
432 if (a->unparseable != b->unparseable)
433 return 0;
434
435 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
436
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
446 case DNS_TYPE_PTR:
447 case DNS_TYPE_NS:
448 case DNS_TYPE_CNAME:
449 case DNS_TYPE_DNAME:
450 return dns_name_equal(a->ptr.name, b->ptr.name);
451
452 case DNS_TYPE_HINFO:
453 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
454 strcaseeq(a->hinfo.os, b->hinfo.os);
455
456 case DNS_TYPE_SPF: /* exactly the same as TXT */
457 case DNS_TYPE_TXT:
458 return dns_txt_item_equal(a->txt.items, b->txt.items);
459
460 case DNS_TYPE_A:
461 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
462
463 case DNS_TYPE_AAAA:
464 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
465
466 case DNS_TYPE_SOA:
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;
479
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
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
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
503 case DNS_TYPE_SSHFP:
504 return a->sshfp.algorithm == b->sshfp.algorithm &&
505 a->sshfp.fptype == b->sshfp.fptype &&
506 a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
507 memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
508
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
516 case DNS_TYPE_RRSIG:
517 /* do the fast comparisons first */
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 ||
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
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
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
544 default:
545 return a->generic.size == b->generic.size &&
546 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
547 }
548 }
549
550 static 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
581 static 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
596 static char *format_types(Bitmap *types) {
597 _cleanup_strv_free_ char **strv = NULL;
598 _cleanup_free_ char *str = NULL;
599 Iterator i;
600 unsigned type;
601 int r;
602
603 BITMAP_FOREACH(type, types, i) {
604 if (dns_type_to_string(type)) {
605 r = strv_extend(&strv, dns_type_to_string(type));
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
615 r = strv_consume(&strv, t);
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
628 static 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
665 int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
666 _cleanup_free_ char *k = NULL, *t = NULL;
667 char *s;
668 int r;
669
670 assert(rr);
671
672 r = dns_resource_key_to_string(rr->key, &k);
673 if (r < 0)
674 return r;
675
676 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
677
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
689 case DNS_TYPE_PTR:
690 case DNS_TYPE_NS:
691 case DNS_TYPE_CNAME:
692 case DNS_TYPE_DNAME:
693 s = strjoin(k, " ", rr->ptr.name, NULL);
694 if (!s)
695 return -ENOMEM;
696
697 break;
698
699 case DNS_TYPE_HINFO:
700 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
701 if (!s)
702 return -ENOMEM;
703 break;
704
705 case DNS_TYPE_SPF: /* exactly the same as TXT */
706 case DNS_TYPE_TXT:
707 t = format_txt(rr->txt.items);
708 if (!t)
709 return -ENOMEM;
710
711 s = strjoin(k, " ", t, NULL);
712 if (!s)
713 return -ENOMEM;
714 break;
715
716 case DNS_TYPE_A: {
717 _cleanup_free_ char *x = NULL;
718
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;
722
723 s = strjoin(k, " ", x, NULL);
724 if (!s)
725 return -ENOMEM;
726 break;
727 }
728
729 case DNS_TYPE_AAAA:
730 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
731 if (r < 0)
732 return r;
733
734 s = strjoin(k, " ", t, NULL);
735 if (!s)
736 return -ENOMEM;
737 break;
738
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
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
762 case DNS_TYPE_LOC:
763 assert(rr->loc.version == 0);
764
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)
772 return -ENOMEM;
773
774 s = strjoin(k, " ", t, NULL);
775 if (!s)
776 return -ENOMEM;
777 break;
778
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
794 case DNS_TYPE_SSHFP:
795 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
796 if (!t)
797 return -ENOMEM;
798
799 r = asprintf(&s, "%s %u %u %s",
800 k,
801 rr->sshfp.algorithm,
802 rr->sshfp.fptype,
803 t);
804 if (r < 0)
805 return -ENOMEM;
806 break;
807
808 case DNS_TYPE_DNSKEY: {
809 const char *alg;
810
811 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
812
813 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
814 if (!t)
815 return -ENOMEM;
816
817 r = asprintf(&s, "%s %u 3 %.*s%.*u %s",
818 k,
819 dnskey_to_flags(rr),
820 alg ? -1 : 0, alg,
821 alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
822 t);
823 if (r < 0)
824 return -ENOMEM;
825 break;
826 }
827
828 case DNS_TYPE_RRSIG: {
829 const char *type, *alg;
830 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
831
832 type = dns_type_to_string(rr->rrsig.type_covered);
833 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
834
835 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
836 if (!t)
837 return -ENOMEM;
838
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
847 /* TYPE?? follows
848 * http://tools.ietf.org/html/rfc3597#section-5 */
849
850 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
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,
858 expiration,
859 inception,
860 rr->rrsig.key_tag,
861 rr->rrsig.signer,
862 t);
863 if (r < 0)
864 return -ENOMEM;
865 break;
866 }
867
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
881 case DNS_TYPE_NSEC3: {
882 _cleanup_free_ char *salt = NULL, *hash = NULL;
883
884 if (rr->nsec3.salt_size > 0) {
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,
903 rr->nsec3.salt_size > 0 ? salt : "-",
904 hash,
905 t);
906 if (r < 0)
907 return -ENOMEM;
908
909 break;
910 }
911
912 default:
913 t = hexmem(rr->generic.data, rr->generic.size);
914 if (!t)
915 return -ENOMEM;
916
917 r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
918 if (r < 0)
919 return -ENOMEM;
920 break;
921 }
922
923 *ret = s;
924 return 0;
925 }
926
927 const char *dns_class_to_string(uint16_t class) {
928
929 switch (class) {
930
931 case DNS_CLASS_IN:
932 return "IN";
933
934 case DNS_CLASS_ANY:
935 return "ANY";
936 }
937
938 return NULL;
939 }
940
941 int 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"))
948 *class = DNS_CLASS_ANY;
949 else
950 return -EINVAL;
951
952 return 0;
953 }
954
955 DnsTxtItem *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
967 bool 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 }