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