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