]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-rr.c
resolved: make expiration error recognizable
[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-table.h"
31 #include "string-util.h"
32 #include "strv.h"
33
34 DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
35 DnsResourceKey *k;
36 size_t l;
37
38 assert(name);
39
40 l = strlen(name);
41 k = malloc0(sizeof(DnsResourceKey) + l + 1);
42 if (!k)
43 return NULL;
44
45 k->n_ref = 1;
46 k->class = class;
47 k->type = type;
48
49 strcpy((char*) k + sizeof(DnsResourceKey), name);
50
51 return k;
52 }
53
54 DnsResourceKey* dns_resource_key_new_cname(const DnsResourceKey *key) {
55 assert(key);
56
57 return dns_resource_key_new(key->class, DNS_TYPE_CNAME, DNS_RESOURCE_KEY_NAME(key));
58 }
59
60 DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) {
61 int r;
62
63 assert(key);
64 assert(cname);
65
66 assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME));
67
68 if (cname->key->type == DNS_TYPE_CNAME)
69 return dns_resource_key_new(key->class, key->type, cname->cname.name);
70 else {
71 DnsResourceKey *k;
72 char *destination = NULL;
73
74 r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination);
75 if (r < 0)
76 return NULL;
77 if (r == 0)
78 return dns_resource_key_ref((DnsResourceKey*) key);
79
80 k = dns_resource_key_new_consume(key->class, key->type, destination);
81 if (!k) {
82 free(destination);
83 return NULL;
84 }
85
86 return k;
87 }
88 }
89
90 int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name) {
91 DnsResourceKey *new_key;
92 char *joined;
93 int r;
94
95 assert(ret);
96 assert(key);
97 assert(name);
98
99 if (dns_name_is_root(name)) {
100 *ret = dns_resource_key_ref(key);
101 return 0;
102 }
103
104 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), name, &joined);
105 if (r < 0)
106 return r;
107
108 new_key = dns_resource_key_new_consume(key->class, key->type, joined);
109 if (!new_key) {
110 free(joined);
111 return -ENOMEM;
112 }
113
114 *ret = new_key;
115 return 0;
116 }
117
118 DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
119 DnsResourceKey *k;
120
121 assert(name);
122
123 k = new0(DnsResourceKey, 1);
124 if (!k)
125 return NULL;
126
127 k->n_ref = 1;
128 k->class = class;
129 k->type = type;
130 k->_name = name;
131
132 return k;
133 }
134
135 DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
136
137 if (!k)
138 return NULL;
139
140 assert(k->n_ref > 0);
141 k->n_ref++;
142
143 return k;
144 }
145
146 DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
147 if (!k)
148 return NULL;
149
150 assert(k->n_ref > 0);
151
152 if (k->n_ref == 1) {
153 free(k->_name);
154 free(k);
155 } else
156 k->n_ref--;
157
158 return NULL;
159 }
160
161 int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
162 int r;
163
164 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
165 if (r <= 0)
166 return r;
167
168 if (a->class != b->class)
169 return 0;
170
171 if (a->type != b->type)
172 return 0;
173
174 return 1;
175 }
176
177 int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain) {
178 int r;
179
180 assert(key);
181 assert(rr);
182
183 /* Checks if an rr matches the specified key. If a search
184 * domain is specified, it will also be checked if the key
185 * with the search domain suffixed might match the RR. */
186
187 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
188 return 0;
189
190 if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
191 return 0;
192
193 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
194 if (r != 0)
195 return r;
196
197 if (search_domain) {
198 _cleanup_free_ char *joined = NULL;
199
200 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
201 if (r < 0)
202 return r;
203
204 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), joined);
205 }
206
207 return 0;
208 }
209
210 int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain) {
211 int r;
212
213 assert(key);
214 assert(rr);
215
216 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
217 return 0;
218
219 if (rr->key->type == DNS_TYPE_CNAME)
220 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(rr->key));
221 else if (rr->key->type == DNS_TYPE_DNAME)
222 r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(rr->key));
223 else
224 return 0;
225
226 if (r != 0)
227 return r;
228
229 if (search_domain) {
230 _cleanup_free_ char *joined = NULL;
231
232 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
233 if (r < 0)
234 return r;
235
236 if (rr->key->type == DNS_TYPE_CNAME)
237 return dns_name_equal(joined, DNS_RESOURCE_KEY_NAME(rr->key));
238 else if (rr->key->type == DNS_TYPE_DNAME)
239 return dns_name_endswith(joined, DNS_RESOURCE_KEY_NAME(rr->key));
240 }
241
242 return 0;
243
244 }
245
246 static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
247 const DnsResourceKey *k = i;
248
249 assert(k);
250
251 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state);
252 siphash24_compress(&k->class, sizeof(k->class), state);
253 siphash24_compress(&k->type, sizeof(k->type), state);
254 }
255
256 static int dns_resource_key_compare_func(const void *a, const void *b) {
257 const DnsResourceKey *x = a, *y = b;
258 int ret;
259
260 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
261 if (ret != 0)
262 return ret;
263
264 if (x->type < y->type)
265 return -1;
266 if (x->type > y->type)
267 return 1;
268
269 if (x->class < y->class)
270 return -1;
271 if (x->class > y->class)
272 return 1;
273
274 return 0;
275 }
276
277 const struct hash_ops dns_resource_key_hash_ops = {
278 .hash = dns_resource_key_hash_func,
279 .compare = dns_resource_key_compare_func
280 };
281
282 int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
283 char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
284 const char *c, *t;
285 char *s;
286
287 c = dns_class_to_string(key->class);
288 if (!c) {
289 sprintf(cbuf, "CLASS%u", key->class);
290 c = cbuf;
291 }
292
293 t = dns_type_to_string(key->type);
294 if (!t){
295 sprintf(tbuf, "TYPE%u", key->type);
296 t = tbuf;
297 }
298
299 if (asprintf(&s, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key), c, t) < 0)
300 return -ENOMEM;
301
302 *ret = s;
303 return 0;
304 }
305
306 DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
307 DnsResourceRecord *rr;
308
309 rr = new0(DnsResourceRecord, 1);
310 if (!rr)
311 return NULL;
312
313 rr->n_ref = 1;
314 rr->key = dns_resource_key_ref(key);
315
316 return rr;
317 }
318
319 DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
320 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
321
322 key = dns_resource_key_new(class, type, name);
323 if (!key)
324 return NULL;
325
326 return dns_resource_record_new(key);
327 }
328
329 DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
330 if (!rr)
331 return NULL;
332
333 assert(rr->n_ref > 0);
334 rr->n_ref++;
335
336 return rr;
337 }
338
339 DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
340 if (!rr)
341 return NULL;
342
343 assert(rr->n_ref > 0);
344
345 if (rr->n_ref > 1) {
346 rr->n_ref--;
347 return NULL;
348 }
349
350 if (rr->key) {
351 switch(rr->key->type) {
352
353 case DNS_TYPE_SRV:
354 free(rr->srv.name);
355 break;
356
357 case DNS_TYPE_PTR:
358 case DNS_TYPE_NS:
359 case DNS_TYPE_CNAME:
360 case DNS_TYPE_DNAME:
361 free(rr->ptr.name);
362 break;
363
364 case DNS_TYPE_HINFO:
365 free(rr->hinfo.cpu);
366 free(rr->hinfo.os);
367 break;
368
369 case DNS_TYPE_TXT:
370 case DNS_TYPE_SPF:
371 dns_txt_item_free_all(rr->txt.items);
372 break;
373
374 case DNS_TYPE_SOA:
375 free(rr->soa.mname);
376 free(rr->soa.rname);
377 break;
378
379 case DNS_TYPE_MX:
380 free(rr->mx.exchange);
381 break;
382
383 case DNS_TYPE_DS:
384 free(rr->ds.digest);
385 break;
386
387 case DNS_TYPE_SSHFP:
388 free(rr->sshfp.fingerprint);
389 break;
390
391 case DNS_TYPE_DNSKEY:
392 free(rr->dnskey.key);
393 break;
394
395 case DNS_TYPE_RRSIG:
396 free(rr->rrsig.signer);
397 free(rr->rrsig.signature);
398 break;
399
400 case DNS_TYPE_NSEC:
401 free(rr->nsec.next_domain_name);
402 bitmap_free(rr->nsec.types);
403 break;
404
405 case DNS_TYPE_NSEC3:
406 free(rr->nsec3.next_hashed_name);
407 free(rr->nsec3.salt);
408 bitmap_free(rr->nsec3.types);
409 break;
410
411 case DNS_TYPE_LOC:
412 case DNS_TYPE_A:
413 case DNS_TYPE_AAAA:
414 break;
415
416 default:
417 free(rr->generic.data);
418 }
419
420 free(rr->wire_format);
421 dns_resource_key_unref(rr->key);
422 }
423
424 free(rr);
425
426 return NULL;
427 }
428
429 int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
430 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
431 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
432 _cleanup_free_ char *ptr = NULL;
433 int r;
434
435 assert(ret);
436 assert(address);
437 assert(hostname);
438
439 r = dns_name_reverse(family, address, &ptr);
440 if (r < 0)
441 return r;
442
443 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
444 if (!key)
445 return -ENOMEM;
446
447 ptr = NULL;
448
449 rr = dns_resource_record_new(key);
450 if (!rr)
451 return -ENOMEM;
452
453 rr->ptr.name = strdup(hostname);
454 if (!rr->ptr.name)
455 return -ENOMEM;
456
457 *ret = rr;
458 rr = NULL;
459
460 return 0;
461 }
462
463 int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
464 DnsResourceRecord *rr;
465
466 assert(ret);
467 assert(address);
468 assert(family);
469
470 if (family == AF_INET) {
471
472 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
473 if (!rr)
474 return -ENOMEM;
475
476 rr->a.in_addr = address->in;
477
478 } else if (family == AF_INET6) {
479
480 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
481 if (!rr)
482 return -ENOMEM;
483
484 rr->aaaa.in6_addr = address->in6;
485 } else
486 return -EAFNOSUPPORT;
487
488 *ret = rr;
489
490 return 0;
491 }
492
493 int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
494 int r;
495
496 assert(a);
497 assert(b);
498
499 r = dns_resource_key_equal(a->key, b->key);
500 if (r <= 0)
501 return r;
502
503 if (a->unparseable != b->unparseable)
504 return 0;
505
506 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
507
508 case DNS_TYPE_SRV:
509 r = dns_name_equal(a->srv.name, b->srv.name);
510 if (r <= 0)
511 return r;
512
513 return a->srv.priority == b->srv.priority &&
514 a->srv.weight == b->srv.weight &&
515 a->srv.port == b->srv.port;
516
517 case DNS_TYPE_PTR:
518 case DNS_TYPE_NS:
519 case DNS_TYPE_CNAME:
520 case DNS_TYPE_DNAME:
521 return dns_name_equal(a->ptr.name, b->ptr.name);
522
523 case DNS_TYPE_HINFO:
524 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
525 strcaseeq(a->hinfo.os, b->hinfo.os);
526
527 case DNS_TYPE_SPF: /* exactly the same as TXT */
528 case DNS_TYPE_TXT:
529 return dns_txt_item_equal(a->txt.items, b->txt.items);
530
531 case DNS_TYPE_A:
532 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
533
534 case DNS_TYPE_AAAA:
535 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
536
537 case DNS_TYPE_SOA:
538 r = dns_name_equal(a->soa.mname, b->soa.mname);
539 if (r <= 0)
540 return r;
541 r = dns_name_equal(a->soa.rname, b->soa.rname);
542 if (r <= 0)
543 return r;
544
545 return a->soa.serial == b->soa.serial &&
546 a->soa.refresh == b->soa.refresh &&
547 a->soa.retry == b->soa.retry &&
548 a->soa.expire == b->soa.expire &&
549 a->soa.minimum == b->soa.minimum;
550
551 case DNS_TYPE_MX:
552 if (a->mx.priority != b->mx.priority)
553 return 0;
554
555 return dns_name_equal(a->mx.exchange, b->mx.exchange);
556
557 case DNS_TYPE_LOC:
558 assert(a->loc.version == b->loc.version);
559
560 return a->loc.size == b->loc.size &&
561 a->loc.horiz_pre == b->loc.horiz_pre &&
562 a->loc.vert_pre == b->loc.vert_pre &&
563 a->loc.latitude == b->loc.latitude &&
564 a->loc.longitude == b->loc.longitude &&
565 a->loc.altitude == b->loc.altitude;
566
567 case DNS_TYPE_DS:
568 return a->ds.key_tag == b->ds.key_tag &&
569 a->ds.algorithm == b->ds.algorithm &&
570 a->ds.digest_type == b->ds.digest_type &&
571 a->ds.digest_size == b->ds.digest_size &&
572 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
573
574 case DNS_TYPE_SSHFP:
575 return a->sshfp.algorithm == b->sshfp.algorithm &&
576 a->sshfp.fptype == b->sshfp.fptype &&
577 a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
578 memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
579
580 case DNS_TYPE_DNSKEY:
581 return a->dnskey.flags == b->dnskey.flags &&
582 a->dnskey.protocol == b->dnskey.protocol &&
583 a->dnskey.algorithm == b->dnskey.algorithm &&
584 a->dnskey.key_size == b->dnskey.key_size &&
585 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
586
587 case DNS_TYPE_RRSIG:
588 /* do the fast comparisons first */
589 if (a->rrsig.type_covered != b->rrsig.type_covered ||
590 a->rrsig.algorithm != b->rrsig.algorithm ||
591 a->rrsig.labels != b->rrsig.labels ||
592 a->rrsig.original_ttl != b->rrsig.original_ttl ||
593 a->rrsig.expiration != b->rrsig.expiration ||
594 a->rrsig.inception != b->rrsig.inception ||
595 a->rrsig.key_tag != b->rrsig.key_tag ||
596 a->rrsig.signature_size != b->rrsig.signature_size ||
597 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
598 return false;
599
600 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
601
602 case DNS_TYPE_NSEC:
603 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
604 bitmap_equal(a->nsec.types, b->nsec.types);
605
606 case DNS_TYPE_NSEC3:
607 return a->nsec3.algorithm == b->nsec3.algorithm &&
608 a->nsec3.flags == b->nsec3.flags &&
609 a->nsec3.iterations == b->nsec3.iterations &&
610 a->nsec3.salt_size == b->nsec3.salt_size &&
611 memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
612 memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
613 bitmap_equal(a->nsec3.types, b->nsec3.types);
614
615 default:
616 return a->generic.size == b->generic.size &&
617 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
618 }
619 }
620
621 static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
622 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
623 char *s;
624 char NS = latitude >= 1U<<31 ? 'N' : 'S';
625 char EW = longitude >= 1U<<31 ? 'E' : 'W';
626
627 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
628 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
629 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
630 double siz = (size >> 4) * exp10((double) (size & 0xF));
631 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
632 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
633
634 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
635 (lat / 60000 / 60),
636 (lat / 60000) % 60,
637 (lat % 60000) / 1000.,
638 NS,
639 (lon / 60000 / 60),
640 (lon / 60000) % 60,
641 (lon % 60000) / 1000.,
642 EW,
643 alt / 100.,
644 siz / 100.,
645 hor / 100.,
646 ver / 100.) < 0)
647 return NULL;
648
649 return s;
650 }
651
652 static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
653 struct tm tm;
654
655 assert(buf);
656 assert(l > strlen("YYYYMMDDHHmmSS"));
657
658 if (!gmtime_r(&sec, &tm))
659 return -EINVAL;
660
661 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
662 return -EINVAL;
663
664 return 0;
665 }
666
667 static char *format_types(Bitmap *types) {
668 _cleanup_strv_free_ char **strv = NULL;
669 _cleanup_free_ char *str = NULL;
670 Iterator i;
671 unsigned type;
672 int r;
673
674 BITMAP_FOREACH(type, types, i) {
675 if (dns_type_to_string(type)) {
676 r = strv_extend(&strv, dns_type_to_string(type));
677 if (r < 0)
678 return NULL;
679 } else {
680 char *t;
681
682 r = asprintf(&t, "TYPE%u", type);
683 if (r < 0)
684 return NULL;
685
686 r = strv_consume(&strv, t);
687 if (r < 0)
688 return NULL;
689 }
690 }
691
692 str = strv_join(strv, " ");
693 if (!str)
694 return NULL;
695
696 return strjoin("( ", str, " )", NULL);
697 }
698
699 static char *format_txt(DnsTxtItem *first) {
700 DnsTxtItem *i;
701 size_t c = 1;
702 char *p, *s;
703
704 LIST_FOREACH(items, i, first)
705 c += i->length * 4 + 3;
706
707 p = s = new(char, c);
708 if (!s)
709 return NULL;
710
711 LIST_FOREACH(items, i, first) {
712 size_t j;
713
714 if (i != first)
715 *(p++) = ' ';
716
717 *(p++) = '"';
718
719 for (j = 0; j < i->length; j++) {
720 if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) {
721 *(p++) = '\\';
722 *(p++) = '0' + (i->data[j] / 100);
723 *(p++) = '0' + ((i->data[j] / 10) % 10);
724 *(p++) = '0' + (i->data[j] % 10);
725 } else
726 *(p++) = i->data[j];
727 }
728
729 *(p++) = '"';
730 }
731
732 *p = 0;
733 return s;
734 }
735
736 int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
737 _cleanup_free_ char *k = NULL, *t = NULL;
738 char *s;
739 int r;
740
741 assert(rr);
742
743 r = dns_resource_key_to_string(rr->key, &k);
744 if (r < 0)
745 return r;
746
747 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
748
749 case DNS_TYPE_SRV:
750 r = asprintf(&s, "%s %u %u %u %s",
751 k,
752 rr->srv.priority,
753 rr->srv.weight,
754 rr->srv.port,
755 strna(rr->srv.name));
756 if (r < 0)
757 return -ENOMEM;
758 break;
759
760 case DNS_TYPE_PTR:
761 case DNS_TYPE_NS:
762 case DNS_TYPE_CNAME:
763 case DNS_TYPE_DNAME:
764 s = strjoin(k, " ", rr->ptr.name, NULL);
765 if (!s)
766 return -ENOMEM;
767
768 break;
769
770 case DNS_TYPE_HINFO:
771 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
772 if (!s)
773 return -ENOMEM;
774 break;
775
776 case DNS_TYPE_SPF: /* exactly the same as TXT */
777 case DNS_TYPE_TXT:
778 t = format_txt(rr->txt.items);
779 if (!t)
780 return -ENOMEM;
781
782 s = strjoin(k, " ", t, NULL);
783 if (!s)
784 return -ENOMEM;
785 break;
786
787 case DNS_TYPE_A: {
788 _cleanup_free_ char *x = NULL;
789
790 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
791 if (r < 0)
792 return r;
793
794 s = strjoin(k, " ", x, NULL);
795 if (!s)
796 return -ENOMEM;
797 break;
798 }
799
800 case DNS_TYPE_AAAA:
801 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
802 if (r < 0)
803 return r;
804
805 s = strjoin(k, " ", t, NULL);
806 if (!s)
807 return -ENOMEM;
808 break;
809
810 case DNS_TYPE_SOA:
811 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
812 k,
813 strna(rr->soa.mname),
814 strna(rr->soa.rname),
815 rr->soa.serial,
816 rr->soa.refresh,
817 rr->soa.retry,
818 rr->soa.expire,
819 rr->soa.minimum);
820 if (r < 0)
821 return -ENOMEM;
822 break;
823
824 case DNS_TYPE_MX:
825 r = asprintf(&s, "%s %u %s",
826 k,
827 rr->mx.priority,
828 rr->mx.exchange);
829 if (r < 0)
830 return -ENOMEM;
831 break;
832
833 case DNS_TYPE_LOC:
834 assert(rr->loc.version == 0);
835
836 t = format_location(rr->loc.latitude,
837 rr->loc.longitude,
838 rr->loc.altitude,
839 rr->loc.size,
840 rr->loc.horiz_pre,
841 rr->loc.vert_pre);
842 if (!t)
843 return -ENOMEM;
844
845 s = strjoin(k, " ", t, NULL);
846 if (!s)
847 return -ENOMEM;
848 break;
849
850 case DNS_TYPE_DS:
851 t = hexmem(rr->ds.digest, rr->ds.digest_size);
852 if (!t)
853 return -ENOMEM;
854
855 r = asprintf(&s, "%s %u %u %u %s",
856 k,
857 rr->ds.key_tag,
858 rr->ds.algorithm,
859 rr->ds.digest_type,
860 t);
861 if (r < 0)
862 return -ENOMEM;
863 break;
864
865 case DNS_TYPE_SSHFP:
866 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
867 if (!t)
868 return -ENOMEM;
869
870 r = asprintf(&s, "%s %u %u %s",
871 k,
872 rr->sshfp.algorithm,
873 rr->sshfp.fptype,
874 t);
875 if (r < 0)
876 return -ENOMEM;
877 break;
878
879 case DNS_TYPE_DNSKEY: {
880 const char *alg;
881
882 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
883
884 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
885 if (!t)
886 return -ENOMEM;
887
888 r = asprintf(&s, "%s %u %u %.*s%.*u %s",
889 k,
890 rr->dnskey.flags,
891 rr->dnskey.protocol,
892 alg ? -1 : 0, alg,
893 alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
894 t);
895 if (r < 0)
896 return -ENOMEM;
897 break;
898 }
899
900 case DNS_TYPE_RRSIG: {
901 const char *type, *alg;
902 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
903
904 type = dns_type_to_string(rr->rrsig.type_covered);
905 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
906
907 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
908 if (!t)
909 return -ENOMEM;
910
911 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
912 if (r < 0)
913 return r;
914
915 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
916 if (r < 0)
917 return r;
918
919 /* TYPE?? follows
920 * http://tools.ietf.org/html/rfc3597#section-5 */
921
922 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
923 k,
924 type ?: "TYPE",
925 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
926 alg ? -1 : 0, alg,
927 alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
928 rr->rrsig.labels,
929 rr->rrsig.original_ttl,
930 expiration,
931 inception,
932 rr->rrsig.key_tag,
933 rr->rrsig.signer,
934 t);
935 if (r < 0)
936 return -ENOMEM;
937 break;
938 }
939
940 case DNS_TYPE_NSEC:
941 t = format_types(rr->nsec.types);
942 if (!t)
943 return -ENOMEM;
944
945 r = asprintf(&s, "%s %s %s",
946 k,
947 rr->nsec.next_domain_name,
948 t);
949 if (r < 0)
950 return -ENOMEM;
951 break;
952
953 case DNS_TYPE_NSEC3: {
954 _cleanup_free_ char *salt = NULL, *hash = NULL;
955
956 if (rr->nsec3.salt_size > 0) {
957 salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
958 if (!salt)
959 return -ENOMEM;
960 }
961
962 hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
963 if (!hash)
964 return -ENOMEM;
965
966 t = format_types(rr->nsec3.types);
967 if (!t)
968 return -ENOMEM;
969
970 r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
971 k,
972 rr->nsec3.algorithm,
973 rr->nsec3.flags,
974 rr->nsec3.iterations,
975 rr->nsec3.salt_size > 0 ? salt : "-",
976 hash,
977 t);
978 if (r < 0)
979 return -ENOMEM;
980
981 break;
982 }
983
984 default:
985 t = hexmem(rr->generic.data, rr->generic.size);
986 if (!t)
987 return -ENOMEM;
988
989 r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
990 if (r < 0)
991 return -ENOMEM;
992 break;
993 }
994
995 *ret = s;
996 return 0;
997 }
998
999 int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {
1000
1001 DnsPacket packet = {
1002 .n_ref = 1,
1003 .protocol = DNS_PROTOCOL_DNS,
1004 .on_stack = true,
1005 .refuse_compression = true,
1006 .canonical_form = canonical,
1007 };
1008
1009 size_t start, rds;
1010 int r;
1011
1012 assert(rr);
1013
1014 /* Generates the RR in wire-format, optionally in the
1015 * canonical form as discussed in the DNSSEC RFC 4034, Section
1016 * 6.2. We allocate a throw-away DnsPacket object on the stack
1017 * here, because we need some book-keeping for memory
1018 * management, and can reuse the DnsPacket serializer, that
1019 * can generate the canonical form, too, but also knows label
1020 * compression and suchlike. */
1021
1022 if (rr->wire_format && rr->wire_format_canonical == canonical)
1023 return 0;
1024
1025 r = dns_packet_append_rr(&packet, rr, &start, &rds);
1026 if (r < 0)
1027 return r;
1028
1029 assert(start == 0);
1030 assert(packet._data);
1031
1032 free(rr->wire_format);
1033 rr->wire_format = packet._data;
1034 rr->wire_format_size = packet.size;
1035 rr->wire_format_rdata_offset = rds;
1036 rr->wire_format_canonical = canonical;
1037
1038 packet._data = NULL;
1039 dns_packet_unref(&packet);
1040
1041 return 0;
1042 }
1043
1044 const char *dns_class_to_string(uint16_t class) {
1045
1046 switch (class) {
1047
1048 case DNS_CLASS_IN:
1049 return "IN";
1050
1051 case DNS_CLASS_ANY:
1052 return "ANY";
1053 }
1054
1055 return NULL;
1056 }
1057
1058 int dns_class_from_string(const char *s, uint16_t *class) {
1059 assert(s);
1060 assert(class);
1061
1062 if (strcaseeq(s, "IN"))
1063 *class = DNS_CLASS_IN;
1064 else if (strcaseeq(s, "ANY"))
1065 *class = DNS_CLASS_ANY;
1066 else
1067 return -EINVAL;
1068
1069 return 0;
1070 }
1071
1072 DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
1073 DnsTxtItem *n;
1074
1075 if (!i)
1076 return NULL;
1077
1078 n = i->items_next;
1079
1080 free(i);
1081 return dns_txt_item_free_all(n);
1082 }
1083
1084 bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
1085
1086 if (!a != !b)
1087 return false;
1088
1089 if (!a)
1090 return true;
1091
1092 if (a->length != b->length)
1093 return false;
1094
1095 if (memcmp(a->data, b->data, a->length) != 0)
1096 return false;
1097
1098 return dns_txt_item_equal(a->items_next, b->items_next);
1099 }
1100
1101 static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
1102 [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
1103 [DNSSEC_ALGORITHM_DH] = "DH",
1104 [DNSSEC_ALGORITHM_DSA] = "DSA",
1105 [DNSSEC_ALGORITHM_ECC] = "ECC",
1106 [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
1107 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1",
1108 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1",
1109 [DNSSEC_ALGORITHM_RSASHA256] = "RSASHA256",
1110 [DNSSEC_ALGORITHM_RSASHA512] = "RSASHA512",
1111 [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
1112 [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
1113 [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
1114 };
1115 DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int);
1116
1117 static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = {
1118 [DNSSEC_DIGEST_SHA1] = "SHA1",
1119 [DNSSEC_DIGEST_SHA256] = "SHA256",
1120 };
1121 DEFINE_STRING_TABLE_LOOKUP(dnssec_digest, int);