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