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