]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-rr.c
bus: prefix custom endpoints with "$UID-"
[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 "strv.h"
25
26 #include "resolved-dns-domain.h"
27 #include "resolved-dns-rr.h"
28 #include "resolved-dns-packet.h"
29 #include "dns-type.h"
30
31 DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
32 DnsResourceKey *k;
33 size_t l;
34
35 assert(name);
36
37 l = strlen(name);
38 k = malloc0(sizeof(DnsResourceKey) + l + 1);
39 if (!k)
40 return NULL;
41
42 k->n_ref = 1;
43 k->class = class;
44 k->type = type;
45
46 strcpy((char*) k + sizeof(DnsResourceKey), name);
47
48 return k;
49 }
50
51 DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
52 DnsResourceKey *k;
53
54 assert(name);
55
56 k = new0(DnsResourceKey, 1);
57 if (!k)
58 return NULL;
59
60 k->n_ref = 1;
61 k->class = class;
62 k->type = type;
63 k->_name = name;
64
65 return k;
66 }
67
68 DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
69
70 if (!k)
71 return NULL;
72
73 assert(k->n_ref > 0);
74 k->n_ref++;
75
76 return k;
77 }
78
79 DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
80 if (!k)
81 return NULL;
82
83 assert(k->n_ref > 0);
84
85 if (k->n_ref == 1) {
86 free(k->_name);
87 free(k);
88 } else
89 k->n_ref--;
90
91 return NULL;
92 }
93
94 int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
95 int r;
96
97 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
98 if (r <= 0)
99 return r;
100
101 if (a->class != b->class)
102 return 0;
103
104 if (a->type != b->type)
105 return 0;
106
107 return 1;
108 }
109
110 int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr) {
111 assert(key);
112 assert(rr);
113
114 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
115 return 0;
116
117 if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
118 return 0;
119
120 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
121 }
122
123 int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr) {
124 assert(key);
125 assert(rr);
126
127 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
128 return 0;
129
130 if (rr->key->type != DNS_TYPE_CNAME)
131 return 0;
132
133 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
134 }
135
136 static unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]) {
137 const DnsResourceKey *k = i;
138 unsigned long ul;
139
140 ul = dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), hash_key);
141 ul = ul * hash_key[0] + ul + k->class;
142 ul = ul * hash_key[1] + ul + k->type;
143
144 return ul;
145 }
146
147 static int dns_resource_key_compare_func(const void *a, const void *b) {
148 const DnsResourceKey *x = a, *y = b;
149 int ret;
150
151 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
152 if (ret != 0)
153 return ret;
154
155 if (x->type < y->type)
156 return -1;
157 if (x->type > y->type)
158 return 1;
159
160 if (x->class < y->class)
161 return -1;
162 if (x->class > y->class)
163 return 1;
164
165 return 0;
166 }
167
168 const struct hash_ops dns_resource_key_hash_ops = {
169 .hash = dns_resource_key_hash_func,
170 .compare = dns_resource_key_compare_func
171 };
172
173 int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
174 char cbuf[DECIMAL_STR_MAX(uint16_t)], tbuf[DECIMAL_STR_MAX(uint16_t)];
175 const char *c, *t;
176 char *s;
177
178 c = dns_class_to_string(key->class);
179 if (!c) {
180 sprintf(cbuf, "%i", key->class);
181 c = cbuf;
182 }
183
184 t = dns_type_to_string(key->type);
185 if (!t){
186 sprintf(tbuf, "%i", key->type);
187 t = tbuf;
188 }
189
190 if (asprintf(&s, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key), c, t) < 0)
191 return -ENOMEM;
192
193 *ret = s;
194 return 0;
195 }
196
197 DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
198 DnsResourceRecord *rr;
199
200 rr = new0(DnsResourceRecord, 1);
201 if (!rr)
202 return NULL;
203
204 rr->n_ref = 1;
205 rr->key = dns_resource_key_ref(key);
206
207 return rr;
208 }
209
210 DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
211 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
212
213 key = dns_resource_key_new(class, type, name);
214 if (!key)
215 return NULL;
216
217 return dns_resource_record_new(key);
218 }
219
220 DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
221 if (!rr)
222 return NULL;
223
224 assert(rr->n_ref > 0);
225 rr->n_ref++;
226
227 return rr;
228 }
229
230 DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
231 if (!rr)
232 return NULL;
233
234 assert(rr->n_ref > 0);
235
236 if (rr->n_ref > 1) {
237 rr->n_ref--;
238 return NULL;
239 }
240
241 if (rr->key) {
242 switch(rr->key->type) {
243
244 case DNS_TYPE_SRV:
245 free(rr->srv.name);
246 break;
247
248 case DNS_TYPE_PTR:
249 case DNS_TYPE_NS:
250 case DNS_TYPE_CNAME:
251 case DNS_TYPE_DNAME:
252 free(rr->ptr.name);
253 break;
254
255 case DNS_TYPE_HINFO:
256 free(rr->hinfo.cpu);
257 free(rr->hinfo.os);
258 break;
259
260 case DNS_TYPE_TXT:
261 case DNS_TYPE_SPF:
262 strv_free(rr->txt.strings);
263 break;
264
265 case DNS_TYPE_SOA:
266 free(rr->soa.mname);
267 free(rr->soa.rname);
268 break;
269
270 case DNS_TYPE_MX:
271 free(rr->mx.exchange);
272 break;
273
274 case DNS_TYPE_SSHFP:
275 free(rr->sshfp.key);
276 break;
277
278 case DNS_TYPE_DNSKEY:
279 free(rr->dnskey.key);
280 break;
281
282 case DNS_TYPE_RRSIG:
283 free(rr->rrsig.signer);
284 free(rr->rrsig.signature);
285 break;
286
287 case DNS_TYPE_LOC:
288 case DNS_TYPE_A:
289 case DNS_TYPE_AAAA:
290 break;
291
292 default:
293 free(rr->generic.data);
294 }
295
296 dns_resource_key_unref(rr->key);
297 }
298
299 free(rr);
300
301 return NULL;
302 }
303
304 int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
305 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
306 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
307 _cleanup_free_ char *ptr = NULL;
308 int r;
309
310 assert(ret);
311 assert(address);
312 assert(hostname);
313
314 r = dns_name_reverse(family, address, &ptr);
315 if (r < 0)
316 return r;
317
318 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
319 if (!key)
320 return -ENOMEM;
321
322 ptr = NULL;
323
324 rr = dns_resource_record_new(key);
325 if (!rr)
326 return -ENOMEM;
327
328 rr->ptr.name = strdup(hostname);
329 if (!rr->ptr.name)
330 return -ENOMEM;
331
332 *ret = rr;
333 rr = NULL;
334
335 return 0;
336 }
337
338 int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
339 int r;
340
341 assert(a);
342 assert(b);
343
344 r = dns_resource_key_equal(a->key, b->key);
345 if (r <= 0)
346 return r;
347
348 if (a->unparseable != b->unparseable)
349 return 0;
350
351 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
352
353 case DNS_TYPE_SRV:
354 r = dns_name_equal(a->srv.name, b->srv.name);
355 if (r <= 0)
356 return r;
357
358 return a->srv.priority == b->srv.priority &&
359 a->srv.weight == b->srv.weight &&
360 a->srv.port == b->srv.port;
361
362 case DNS_TYPE_PTR:
363 case DNS_TYPE_NS:
364 case DNS_TYPE_CNAME:
365 case DNS_TYPE_DNAME:
366 return dns_name_equal(a->ptr.name, b->ptr.name);
367
368 case DNS_TYPE_HINFO:
369 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
370 strcaseeq(a->hinfo.os, b->hinfo.os);
371
372 case DNS_TYPE_SPF: /* exactly the same as TXT */
373 case DNS_TYPE_TXT: {
374 int i;
375
376 for (i = 0; a->txt.strings[i] || b->txt.strings[i]; i++)
377 if (!streq_ptr(a->txt.strings[i], b->txt.strings[i]))
378 return false;
379 return true;
380 }
381
382 case DNS_TYPE_A:
383 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
384
385 case DNS_TYPE_AAAA:
386 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
387
388 case DNS_TYPE_SOA:
389 r = dns_name_equal(a->soa.mname, b->soa.mname);
390 if (r <= 0)
391 return r;
392 r = dns_name_equal(a->soa.rname, b->soa.rname);
393 if (r <= 0)
394 return r;
395
396 return a->soa.serial == b->soa.serial &&
397 a->soa.refresh == b->soa.refresh &&
398 a->soa.retry == b->soa.retry &&
399 a->soa.expire == b->soa.expire &&
400 a->soa.minimum == b->soa.minimum;
401
402 case DNS_TYPE_MX:
403 if (a->mx.priority != b->mx.priority)
404 return 0;
405
406 return dns_name_equal(a->mx.exchange, b->mx.exchange);
407
408 case DNS_TYPE_LOC:
409 assert(a->loc.version == b->loc.version);
410
411 return a->loc.size == b->loc.size &&
412 a->loc.horiz_pre == b->loc.horiz_pre &&
413 a->loc.vert_pre == b->loc.vert_pre &&
414 a->loc.latitude == b->loc.latitude &&
415 a->loc.longitude == b->loc.longitude &&
416 a->loc.altitude == b->loc.altitude;
417
418 case DNS_TYPE_SSHFP:
419 return a->sshfp.algorithm == b->sshfp.algorithm &&
420 a->sshfp.fptype == b->sshfp.fptype &&
421 a->sshfp.key_size == b->sshfp.key_size &&
422 memcmp(a->sshfp.key, b->sshfp.key, a->sshfp.key_size) == 0;
423
424 case DNS_TYPE_DNSKEY:
425 return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag &&
426 a->dnskey.sep_flag == b->dnskey.sep_flag &&
427 a->dnskey.algorithm == b->dnskey.algorithm &&
428 a->dnskey.key_size == b->dnskey.key_size &&
429 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
430
431 case DNS_TYPE_RRSIG:
432 /* do the fast comparisons first */
433 if (a->rrsig.type_covered != b->rrsig.type_covered ||
434 a->rrsig.algorithm != b->rrsig.algorithm ||
435 a->rrsig.labels != b->rrsig.labels ||
436 a->rrsig.original_ttl != b->rrsig.original_ttl ||
437 a->rrsig.expiration != b->rrsig.expiration ||
438 a->rrsig.inception != b->rrsig.inception ||
439 a->rrsig.key_tag != b->rrsig.key_tag ||
440 a->rrsig.signature_size != b->rrsig.signature_size ||
441 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
442 return false;
443
444 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
445
446 default:
447 return a->generic.size == b->generic.size &&
448 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
449 }
450 }
451
452 static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
453 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
454 char *s;
455 char NS = latitude >= 1U<<31 ? 'N' : 'S';
456 char EW = longitude >= 1U<<31 ? 'E' : 'W';
457
458 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
459 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
460 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
461 double siz = (size >> 4) * exp10((double) (size & 0xF));
462 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
463 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
464
465 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
466 (lat / 60000 / 60),
467 (lat / 60000) % 60,
468 (lat % 60000) / 1000.,
469 NS,
470 (lon / 60000 / 60),
471 (lon / 60000) % 60,
472 (lon % 60000) / 1000.,
473 EW,
474 alt / 100.,
475 siz / 100.,
476 hor / 100.,
477 ver / 100.) < 0)
478 return NULL;
479
480 return s;
481 }
482
483 int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
484 _cleanup_free_ char *k = NULL, *t = NULL;
485 char *s;
486 int r;
487
488 assert(rr);
489
490 r = dns_resource_key_to_string(rr->key, &k);
491 if (r < 0)
492 return r;
493
494 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
495
496 case DNS_TYPE_SRV:
497 r = asprintf(&s, "%s %u %u %u %s",
498 k,
499 rr->srv.priority,
500 rr->srv.weight,
501 rr->srv.port,
502 strna(rr->srv.name));
503 if (r < 0)
504 return -ENOMEM;
505 break;
506
507 case DNS_TYPE_PTR:
508 case DNS_TYPE_NS:
509 case DNS_TYPE_CNAME:
510 case DNS_TYPE_DNAME:
511 s = strjoin(k, " ", rr->ptr.name, NULL);
512 if (!s)
513 return -ENOMEM;
514
515 break;
516
517 case DNS_TYPE_HINFO:
518 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
519 if (!s)
520 return -ENOMEM;
521 break;
522
523 case DNS_TYPE_SPF: /* exactly the same as TXT */
524 case DNS_TYPE_TXT:
525 t = strv_join_quoted(rr->txt.strings);
526 if (!t)
527 return -ENOMEM;
528
529 s = strjoin(k, " ", t, NULL);
530 if (!s)
531 return -ENOMEM;
532
533 break;
534
535 case DNS_TYPE_A: {
536 _cleanup_free_ char *x = NULL;
537
538 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
539 if (r < 0)
540 return r;
541
542 s = strjoin(k, " ", x, NULL);
543 if (!s)
544 return -ENOMEM;
545 break;
546 }
547
548 case DNS_TYPE_AAAA:
549 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
550 if (r < 0)
551 return r;
552
553 s = strjoin(k, " ", t, NULL);
554 if (!s)
555 return -ENOMEM;
556 break;
557
558 case DNS_TYPE_SOA:
559 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
560 k,
561 strna(rr->soa.mname),
562 strna(rr->soa.rname),
563 rr->soa.serial,
564 rr->soa.refresh,
565 rr->soa.retry,
566 rr->soa.expire,
567 rr->soa.minimum);
568 if (r < 0)
569 return -ENOMEM;
570 break;
571
572 case DNS_TYPE_MX:
573 r = asprintf(&s, "%s %u %s",
574 k,
575 rr->mx.priority,
576 rr->mx.exchange);
577 if (r < 0)
578 return -ENOMEM;
579 break;
580
581 case DNS_TYPE_LOC:
582 assert(rr->loc.version == 0);
583
584 t = format_location(rr->loc.latitude,
585 rr->loc.longitude,
586 rr->loc.altitude,
587 rr->loc.size,
588 rr->loc.horiz_pre,
589 rr->loc.vert_pre);
590 if (!t)
591 return -ENOMEM;
592
593 s = strjoin(k, " ", t, NULL);
594 if (!s)
595 return -ENOMEM;
596 break;
597
598 case DNS_TYPE_SSHFP:
599 t = hexmem(rr->sshfp.key, rr->sshfp.key_size);
600 if (!t)
601 return -ENOMEM;
602
603 r = asprintf(&s, "%s %u %u %s",
604 k,
605 rr->sshfp.algorithm,
606 rr->sshfp.fptype,
607 t);
608 if (r < 0)
609 return -ENOMEM;
610 break;
611
612 case DNS_TYPE_DNSKEY: {
613 const char *alg;
614
615 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
616
617 t = hexmem(rr->dnskey.key, rr->dnskey.key_size);
618 if (!t)
619 return -ENOMEM;
620
621 r = asprintf(&s, "%s %u 3 %.*s%.*u %s",
622 k,
623 dnskey_to_flags(rr),
624 alg ? -1 : 0, alg,
625 alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
626 t);
627 if (r < 0)
628 return -ENOMEM;
629 break;
630 }
631
632 case DNS_TYPE_RRSIG: {
633 const char *type, *alg;
634
635 type = dns_type_to_string(rr->rrsig.type_covered);
636 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
637
638 t = hexmem(rr->rrsig.signature, rr->rrsig.signature_size);
639 if (!t)
640 return -ENOMEM;
641
642 /* TYPE?? follows
643 * http://tools.ietf.org/html/rfc3597#section-5 */
644
645 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %u %u %u %s %s",
646 k,
647 type ?: "TYPE",
648 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
649 alg ? -1 : 0, alg,
650 alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
651 rr->rrsig.labels,
652 rr->rrsig.original_ttl,
653 rr->rrsig.expiration,
654 rr->rrsig.inception,
655 rr->rrsig.key_tag,
656 rr->rrsig.signer,
657 t);
658 if (r < 0)
659 return -ENOMEM;
660 break;
661 }
662
663 default:
664 t = hexmem(rr->generic.data, rr->generic.size);
665 if (!t)
666 return -ENOMEM;
667
668 s = strjoin(k, " ", t, NULL);
669 if (!s)
670 return -ENOMEM;
671 break;
672 }
673
674 *ret = s;
675 return 0;
676 }
677
678 const char *dns_class_to_string(uint16_t class) {
679
680 switch (class) {
681
682 case DNS_CLASS_IN:
683 return "IN";
684
685 case DNS_CLASS_ANY:
686 return "ANY";
687 }
688
689 return NULL;
690 }
691
692 int dns_class_from_string(const char *s, uint16_t *class) {
693 assert(s);
694 assert(class);
695
696 if (strcaseeq(s, "IN"))
697 *class = DNS_CLASS_IN;
698 else if (strcaseeq(s, "ANY"))
699 *class = DNS_TYPE_ANY;
700 else
701 return -EINVAL;
702
703 return 0;
704 }