]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-rr.c
resolved: use CLAMP() intsead of MIN(MAX())
[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_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
84 int 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
112 DnsResourceKey* 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
129 DnsResourceKey* 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
144 DnsResourceKey* 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
160 bool 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
168 int 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
187 int 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
223 int 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
258 int 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
273 static 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
283 static 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
304 const struct hash_ops dns_resource_key_hash_ops = {
305 .hash = dns_resource_key_hash_func,
306 .compare = dns_resource_key_compare_func
307 };
308
309 int 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
333 DnsResourceRecord* 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 rr->expiry = USEC_INFINITY;
343
344 return rr;
345 }
346
347 DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
348 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
349
350 key = dns_resource_key_new(class, type, name);
351 if (!key)
352 return NULL;
353
354 return dns_resource_record_new(key);
355 }
356
357 DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
358 if (!rr)
359 return NULL;
360
361 assert(rr->n_ref > 0);
362 rr->n_ref++;
363
364 return rr;
365 }
366
367 DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
368 if (!rr)
369 return NULL;
370
371 assert(rr->n_ref > 0);
372
373 if (rr->n_ref > 1) {
374 rr->n_ref--;
375 return NULL;
376 }
377
378 if (rr->key) {
379 switch(rr->key->type) {
380
381 case DNS_TYPE_SRV:
382 free(rr->srv.name);
383 break;
384
385 case DNS_TYPE_PTR:
386 case DNS_TYPE_NS:
387 case DNS_TYPE_CNAME:
388 case DNS_TYPE_DNAME:
389 free(rr->ptr.name);
390 break;
391
392 case DNS_TYPE_HINFO:
393 free(rr->hinfo.cpu);
394 free(rr->hinfo.os);
395 break;
396
397 case DNS_TYPE_TXT:
398 case DNS_TYPE_SPF:
399 dns_txt_item_free_all(rr->txt.items);
400 break;
401
402 case DNS_TYPE_SOA:
403 free(rr->soa.mname);
404 free(rr->soa.rname);
405 break;
406
407 case DNS_TYPE_MX:
408 free(rr->mx.exchange);
409 break;
410
411 case DNS_TYPE_DS:
412 free(rr->ds.digest);
413 break;
414
415 case DNS_TYPE_SSHFP:
416 free(rr->sshfp.fingerprint);
417 break;
418
419 case DNS_TYPE_DNSKEY:
420 free(rr->dnskey.key);
421 break;
422
423 case DNS_TYPE_RRSIG:
424 free(rr->rrsig.signer);
425 free(rr->rrsig.signature);
426 break;
427
428 case DNS_TYPE_NSEC:
429 free(rr->nsec.next_domain_name);
430 bitmap_free(rr->nsec.types);
431 break;
432
433 case DNS_TYPE_NSEC3:
434 free(rr->nsec3.next_hashed_name);
435 free(rr->nsec3.salt);
436 bitmap_free(rr->nsec3.types);
437 break;
438
439 case DNS_TYPE_LOC:
440 case DNS_TYPE_A:
441 case DNS_TYPE_AAAA:
442 break;
443
444 default:
445 free(rr->generic.data);
446 }
447
448 free(rr->wire_format);
449 dns_resource_key_unref(rr->key);
450 }
451
452 free(rr->to_string);
453 free(rr);
454
455 return NULL;
456 }
457
458 int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
459 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
460 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
461 _cleanup_free_ char *ptr = NULL;
462 int r;
463
464 assert(ret);
465 assert(address);
466 assert(hostname);
467
468 r = dns_name_reverse(family, address, &ptr);
469 if (r < 0)
470 return r;
471
472 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
473 if (!key)
474 return -ENOMEM;
475
476 ptr = NULL;
477
478 rr = dns_resource_record_new(key);
479 if (!rr)
480 return -ENOMEM;
481
482 rr->ptr.name = strdup(hostname);
483 if (!rr->ptr.name)
484 return -ENOMEM;
485
486 *ret = rr;
487 rr = NULL;
488
489 return 0;
490 }
491
492 int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
493 DnsResourceRecord *rr;
494
495 assert(ret);
496 assert(address);
497 assert(family);
498
499 if (family == AF_INET) {
500
501 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
502 if (!rr)
503 return -ENOMEM;
504
505 rr->a.in_addr = address->in;
506
507 } else if (family == AF_INET6) {
508
509 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
510 if (!rr)
511 return -ENOMEM;
512
513 rr->aaaa.in6_addr = address->in6;
514 } else
515 return -EAFNOSUPPORT;
516
517 *ret = rr;
518
519 return 0;
520 }
521
522 int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
523 int r;
524
525 assert(a);
526 assert(b);
527
528 if (a == b)
529 return 1;
530
531 r = dns_resource_key_equal(a->key, b->key);
532 if (r <= 0)
533 return r;
534
535 if (a->unparseable != b->unparseable)
536 return 0;
537
538 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
539
540 case DNS_TYPE_SRV:
541 r = dns_name_equal(a->srv.name, b->srv.name);
542 if (r <= 0)
543 return r;
544
545 return a->srv.priority == b->srv.priority &&
546 a->srv.weight == b->srv.weight &&
547 a->srv.port == b->srv.port;
548
549 case DNS_TYPE_PTR:
550 case DNS_TYPE_NS:
551 case DNS_TYPE_CNAME:
552 case DNS_TYPE_DNAME:
553 return dns_name_equal(a->ptr.name, b->ptr.name);
554
555 case DNS_TYPE_HINFO:
556 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
557 strcaseeq(a->hinfo.os, b->hinfo.os);
558
559 case DNS_TYPE_SPF: /* exactly the same as TXT */
560 case DNS_TYPE_TXT:
561 return dns_txt_item_equal(a->txt.items, b->txt.items);
562
563 case DNS_TYPE_A:
564 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
565
566 case DNS_TYPE_AAAA:
567 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
568
569 case DNS_TYPE_SOA:
570 r = dns_name_equal(a->soa.mname, b->soa.mname);
571 if (r <= 0)
572 return r;
573 r = dns_name_equal(a->soa.rname, b->soa.rname);
574 if (r <= 0)
575 return r;
576
577 return a->soa.serial == b->soa.serial &&
578 a->soa.refresh == b->soa.refresh &&
579 a->soa.retry == b->soa.retry &&
580 a->soa.expire == b->soa.expire &&
581 a->soa.minimum == b->soa.minimum;
582
583 case DNS_TYPE_MX:
584 if (a->mx.priority != b->mx.priority)
585 return 0;
586
587 return dns_name_equal(a->mx.exchange, b->mx.exchange);
588
589 case DNS_TYPE_LOC:
590 assert(a->loc.version == b->loc.version);
591
592 return a->loc.size == b->loc.size &&
593 a->loc.horiz_pre == b->loc.horiz_pre &&
594 a->loc.vert_pre == b->loc.vert_pre &&
595 a->loc.latitude == b->loc.latitude &&
596 a->loc.longitude == b->loc.longitude &&
597 a->loc.altitude == b->loc.altitude;
598
599 case DNS_TYPE_DS:
600 return a->ds.key_tag == b->ds.key_tag &&
601 a->ds.algorithm == b->ds.algorithm &&
602 a->ds.digest_type == b->ds.digest_type &&
603 a->ds.digest_size == b->ds.digest_size &&
604 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
605
606 case DNS_TYPE_SSHFP:
607 return a->sshfp.algorithm == b->sshfp.algorithm &&
608 a->sshfp.fptype == b->sshfp.fptype &&
609 a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
610 memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
611
612 case DNS_TYPE_DNSKEY:
613 return a->dnskey.flags == b->dnskey.flags &&
614 a->dnskey.protocol == b->dnskey.protocol &&
615 a->dnskey.algorithm == b->dnskey.algorithm &&
616 a->dnskey.key_size == b->dnskey.key_size &&
617 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
618
619 case DNS_TYPE_RRSIG:
620 /* do the fast comparisons first */
621 if (a->rrsig.type_covered != b->rrsig.type_covered ||
622 a->rrsig.algorithm != b->rrsig.algorithm ||
623 a->rrsig.labels != b->rrsig.labels ||
624 a->rrsig.original_ttl != b->rrsig.original_ttl ||
625 a->rrsig.expiration != b->rrsig.expiration ||
626 a->rrsig.inception != b->rrsig.inception ||
627 a->rrsig.key_tag != b->rrsig.key_tag ||
628 a->rrsig.signature_size != b->rrsig.signature_size ||
629 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
630 return false;
631
632 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
633
634 case DNS_TYPE_NSEC:
635 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
636 bitmap_equal(a->nsec.types, b->nsec.types);
637
638 case DNS_TYPE_NSEC3:
639 return a->nsec3.algorithm == b->nsec3.algorithm &&
640 a->nsec3.flags == b->nsec3.flags &&
641 a->nsec3.iterations == b->nsec3.iterations &&
642 a->nsec3.salt_size == b->nsec3.salt_size &&
643 memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
644 memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
645 bitmap_equal(a->nsec3.types, b->nsec3.types);
646
647 default:
648 return a->generic.size == b->generic.size &&
649 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
650 }
651 }
652
653 static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
654 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
655 char *s;
656 char NS = latitude >= 1U<<31 ? 'N' : 'S';
657 char EW = longitude >= 1U<<31 ? 'E' : 'W';
658
659 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
660 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
661 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
662 double siz = (size >> 4) * exp10((double) (size & 0xF));
663 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
664 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
665
666 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
667 (lat / 60000 / 60),
668 (lat / 60000) % 60,
669 (lat % 60000) / 1000.,
670 NS,
671 (lon / 60000 / 60),
672 (lon / 60000) % 60,
673 (lon % 60000) / 1000.,
674 EW,
675 alt / 100.,
676 siz / 100.,
677 hor / 100.,
678 ver / 100.) < 0)
679 return NULL;
680
681 return s;
682 }
683
684 static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
685 struct tm tm;
686
687 assert(buf);
688 assert(l > strlen("YYYYMMDDHHmmSS"));
689
690 if (!gmtime_r(&sec, &tm))
691 return -EINVAL;
692
693 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
694 return -EINVAL;
695
696 return 0;
697 }
698
699 static char *format_types(Bitmap *types) {
700 _cleanup_strv_free_ char **strv = NULL;
701 _cleanup_free_ char *str = NULL;
702 Iterator i;
703 unsigned type;
704 int r;
705
706 BITMAP_FOREACH(type, types, i) {
707 if (dns_type_to_string(type)) {
708 r = strv_extend(&strv, dns_type_to_string(type));
709 if (r < 0)
710 return NULL;
711 } else {
712 char *t;
713
714 r = asprintf(&t, "TYPE%u", type);
715 if (r < 0)
716 return NULL;
717
718 r = strv_consume(&strv, t);
719 if (r < 0)
720 return NULL;
721 }
722 }
723
724 str = strv_join(strv, " ");
725 if (!str)
726 return NULL;
727
728 return strjoin("( ", str, " )", NULL);
729 }
730
731 static char *format_txt(DnsTxtItem *first) {
732 DnsTxtItem *i;
733 size_t c = 1;
734 char *p, *s;
735
736 LIST_FOREACH(items, i, first)
737 c += i->length * 4 + 3;
738
739 p = s = new(char, c);
740 if (!s)
741 return NULL;
742
743 LIST_FOREACH(items, i, first) {
744 size_t j;
745
746 if (i != first)
747 *(p++) = ' ';
748
749 *(p++) = '"';
750
751 for (j = 0; j < i->length; j++) {
752 if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) {
753 *(p++) = '\\';
754 *(p++) = '0' + (i->data[j] / 100);
755 *(p++) = '0' + ((i->data[j] / 10) % 10);
756 *(p++) = '0' + (i->data[j] % 10);
757 } else
758 *(p++) = i->data[j];
759 }
760
761 *(p++) = '"';
762 }
763
764 *p = 0;
765 return s;
766 }
767
768 const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
769 _cleanup_free_ char *k = NULL, *t = NULL;
770 char *s;
771 int r;
772
773 assert(rr);
774
775 if (rr->to_string)
776 return rr->to_string;
777
778 r = dns_resource_key_to_string(rr->key, &k);
779 if (r < 0)
780 return NULL;
781
782 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
783
784 case DNS_TYPE_SRV:
785 r = asprintf(&s, "%s %u %u %u %s",
786 k,
787 rr->srv.priority,
788 rr->srv.weight,
789 rr->srv.port,
790 strna(rr->srv.name));
791 if (r < 0)
792 return NULL;
793 break;
794
795 case DNS_TYPE_PTR:
796 case DNS_TYPE_NS:
797 case DNS_TYPE_CNAME:
798 case DNS_TYPE_DNAME:
799 s = strjoin(k, " ", rr->ptr.name, NULL);
800 if (!s)
801 return NULL;
802
803 break;
804
805 case DNS_TYPE_HINFO:
806 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
807 if (!s)
808 return NULL;
809 break;
810
811 case DNS_TYPE_SPF: /* exactly the same as TXT */
812 case DNS_TYPE_TXT:
813 t = format_txt(rr->txt.items);
814 if (!t)
815 return NULL;
816
817 s = strjoin(k, " ", t, NULL);
818 if (!s)
819 return NULL;
820 break;
821
822 case DNS_TYPE_A: {
823 _cleanup_free_ char *x = NULL;
824
825 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
826 if (r < 0)
827 return NULL;
828
829 s = strjoin(k, " ", x, NULL);
830 if (!s)
831 return NULL;
832 break;
833 }
834
835 case DNS_TYPE_AAAA:
836 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
837 if (r < 0)
838 return NULL;
839
840 s = strjoin(k, " ", t, NULL);
841 if (!s)
842 return NULL;
843 break;
844
845 case DNS_TYPE_SOA:
846 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
847 k,
848 strna(rr->soa.mname),
849 strna(rr->soa.rname),
850 rr->soa.serial,
851 rr->soa.refresh,
852 rr->soa.retry,
853 rr->soa.expire,
854 rr->soa.minimum);
855 if (r < 0)
856 return NULL;
857 break;
858
859 case DNS_TYPE_MX:
860 r = asprintf(&s, "%s %u %s",
861 k,
862 rr->mx.priority,
863 rr->mx.exchange);
864 if (r < 0)
865 return NULL;
866 break;
867
868 case DNS_TYPE_LOC:
869 assert(rr->loc.version == 0);
870
871 t = format_location(rr->loc.latitude,
872 rr->loc.longitude,
873 rr->loc.altitude,
874 rr->loc.size,
875 rr->loc.horiz_pre,
876 rr->loc.vert_pre);
877 if (!t)
878 return NULL;
879
880 s = strjoin(k, " ", t, NULL);
881 if (!s)
882 return NULL;
883 break;
884
885 case DNS_TYPE_DS:
886 t = hexmem(rr->ds.digest, rr->ds.digest_size);
887 if (!t)
888 return NULL;
889
890 r = asprintf(&s, "%s %u %u %u %s",
891 k,
892 rr->ds.key_tag,
893 rr->ds.algorithm,
894 rr->ds.digest_type,
895 t);
896 if (r < 0)
897 return NULL;
898 break;
899
900 case DNS_TYPE_SSHFP:
901 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
902 if (!t)
903 return NULL;
904
905 r = asprintf(&s, "%s %u %u %s",
906 k,
907 rr->sshfp.algorithm,
908 rr->sshfp.fptype,
909 t);
910 if (r < 0)
911 return NULL;
912 break;
913
914 case DNS_TYPE_DNSKEY: {
915 const char *alg;
916
917 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
918
919 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
920 if (!t)
921 return NULL;
922
923 r = asprintf(&s, "%s %u %u %.*s%.*u %s",
924 k,
925 rr->dnskey.flags,
926 rr->dnskey.protocol,
927 alg ? -1 : 0, alg,
928 alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
929 t);
930 if (r < 0)
931 return NULL;
932 break;
933 }
934
935 case DNS_TYPE_RRSIG: {
936 const char *type, *alg;
937 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
938
939 type = dns_type_to_string(rr->rrsig.type_covered);
940 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
941
942 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
943 if (!t)
944 return NULL;
945
946 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
947 if (r < 0)
948 return NULL;
949
950 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
951 if (r < 0)
952 return NULL;
953
954 /* TYPE?? follows
955 * http://tools.ietf.org/html/rfc3597#section-5 */
956
957 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
958 k,
959 type ?: "TYPE",
960 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
961 alg ? -1 : 0, alg,
962 alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
963 rr->rrsig.labels,
964 rr->rrsig.original_ttl,
965 expiration,
966 inception,
967 rr->rrsig.key_tag,
968 rr->rrsig.signer,
969 t);
970 if (r < 0)
971 return NULL;
972 break;
973 }
974
975 case DNS_TYPE_NSEC:
976 t = format_types(rr->nsec.types);
977 if (!t)
978 return NULL;
979
980 r = asprintf(&s, "%s %s %s",
981 k,
982 rr->nsec.next_domain_name,
983 t);
984 if (r < 0)
985 return NULL;
986 break;
987
988 case DNS_TYPE_NSEC3: {
989 _cleanup_free_ char *salt = NULL, *hash = NULL;
990
991 if (rr->nsec3.salt_size > 0) {
992 salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
993 if (!salt)
994 return NULL;
995 }
996
997 hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
998 if (!hash)
999 return NULL;
1000
1001 t = format_types(rr->nsec3.types);
1002 if (!t)
1003 return NULL;
1004
1005 r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
1006 k,
1007 rr->nsec3.algorithm,
1008 rr->nsec3.flags,
1009 rr->nsec3.iterations,
1010 rr->nsec3.salt_size > 0 ? salt : "-",
1011 hash,
1012 t);
1013 if (r < 0)
1014 return NULL;
1015
1016 break;
1017 }
1018
1019 default:
1020 t = hexmem(rr->generic.data, rr->generic.size);
1021 if (!t)
1022 return NULL;
1023
1024 r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
1025 if (r < 0)
1026 return NULL;
1027 break;
1028 }
1029
1030 rr->to_string = s;
1031 return s;
1032 }
1033
1034 int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {
1035
1036 DnsPacket packet = {
1037 .n_ref = 1,
1038 .protocol = DNS_PROTOCOL_DNS,
1039 .on_stack = true,
1040 .refuse_compression = true,
1041 .canonical_form = canonical,
1042 };
1043
1044 size_t start, rds;
1045 int r;
1046
1047 assert(rr);
1048
1049 /* Generates the RR in wire-format, optionally in the
1050 * canonical form as discussed in the DNSSEC RFC 4034, Section
1051 * 6.2. We allocate a throw-away DnsPacket object on the stack
1052 * here, because we need some book-keeping for memory
1053 * management, and can reuse the DnsPacket serializer, that
1054 * can generate the canonical form, too, but also knows label
1055 * compression and suchlike. */
1056
1057 if (rr->wire_format && rr->wire_format_canonical == canonical)
1058 return 0;
1059
1060 r = dns_packet_append_rr(&packet, rr, &start, &rds);
1061 if (r < 0)
1062 return r;
1063
1064 assert(start == 0);
1065 assert(packet._data);
1066
1067 free(rr->wire_format);
1068 rr->wire_format = packet._data;
1069 rr->wire_format_size = packet.size;
1070 rr->wire_format_rdata_offset = rds;
1071 rr->wire_format_canonical = canonical;
1072
1073 packet._data = NULL;
1074 dns_packet_unref(&packet);
1075
1076 return 0;
1077 }
1078
1079 DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
1080 DnsTxtItem *n;
1081
1082 if (!i)
1083 return NULL;
1084
1085 n = i->items_next;
1086
1087 free(i);
1088 return dns_txt_item_free_all(n);
1089 }
1090
1091 bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
1092
1093 if (a == b)
1094 return true;
1095
1096 if (!a != !b)
1097 return false;
1098
1099 if (!a)
1100 return true;
1101
1102 if (a->length != b->length)
1103 return false;
1104
1105 if (memcmp(a->data, b->data, a->length) != 0)
1106 return false;
1107
1108 return dns_txt_item_equal(a->items_next, b->items_next);
1109 }
1110
1111 static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
1112 [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
1113 [DNSSEC_ALGORITHM_DH] = "DH",
1114 [DNSSEC_ALGORITHM_DSA] = "DSA",
1115 [DNSSEC_ALGORITHM_ECC] = "ECC",
1116 [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
1117 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1",
1118 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1",
1119 [DNSSEC_ALGORITHM_RSASHA256] = "RSASHA256",
1120 [DNSSEC_ALGORITHM_RSASHA512] = "RSASHA512",
1121 [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
1122 [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
1123 [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
1124 };
1125 DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int);
1126
1127 static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = {
1128 [DNSSEC_DIGEST_SHA1] = "SHA1",
1129 [DNSSEC_DIGEST_SHA256] = "SHA256",
1130 };
1131 DEFINE_STRING_TABLE_LOOKUP(dnssec_digest, int);