]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-rr.c
update TODO
[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
183 s = strjoin(DNS_RESOURCE_KEY_NAME(key), " ", c, " ", t, NULL);
184 if (!s)
185 return -ENOMEM;
186
187 *ret = s;
188 return 0;
189}
190
faa133f3 191DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
74b2466e
LP
192 DnsResourceRecord *rr;
193
194 rr = new0(DnsResourceRecord, 1);
195 if (!rr)
196 return NULL;
197
198 rr->n_ref = 1;
faa133f3
LP
199 rr->key = dns_resource_key_ref(key);
200
74b2466e
LP
201 return rr;
202}
203
8bf52d3d
LP
204DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
205 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
206
207 key = dns_resource_key_new(class, type, name);
208 if (!key)
209 return NULL;
210
211 return dns_resource_record_new(key);
212}
213
74b2466e
LP
214DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
215 if (!rr)
216 return NULL;
217
218 assert(rr->n_ref > 0);
219 rr->n_ref++;
220
221 return rr;
222}
223
224DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
225 if (!rr)
226 return NULL;
227
228 assert(rr->n_ref > 0);
229
230 if (rr->n_ref > 1) {
231 rr->n_ref--;
232 return NULL;
233 }
234
faa133f3 235 if (rr->key) {
9de3e329
ZJS
236 switch(rr->key->type) {
237 case DNS_TYPE_PTR:
238 case DNS_TYPE_NS:
239 case DNS_TYPE_CNAME:
faa133f3 240 free(rr->ptr.name);
9de3e329
ZJS
241 break;
242 case DNS_TYPE_HINFO:
faa133f3
LP
243 free(rr->hinfo.cpu);
244 free(rr->hinfo.os);
9de3e329
ZJS
245 break;
246 case DNS_TYPE_SPF:
247 case DNS_TYPE_TXT:
2e276efc 248 strv_free(rr->txt.strings);
9de3e329
ZJS
249 break;
250 case DNS_TYPE_SOA:
7e8e0422
LP
251 free(rr->soa.mname);
252 free(rr->soa.rname);
9de3e329
ZJS
253 break;
254 case DNS_TYPE_MX:
946c7094 255 free(rr->mx.exchange);
9de3e329 256 break;
0dae31d4 257 case DNS_TYPE_LOC:
9de3e329
ZJS
258 case DNS_TYPE_A:
259 case DNS_TYPE_AAAA:
260 break;
261 default:
faa133f3 262 free(rr->generic.data);
9de3e329 263 }
322345fd 264
faa133f3
LP
265 dns_resource_key_unref(rr->key);
266 }
322345fd 267
faa133f3 268 free(rr);
322345fd 269
322345fd
LP
270 return NULL;
271}
272
623a4c97
LP
273int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
274 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
275 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
276 _cleanup_free_ char *ptr = NULL;
277 int r;
278
279 assert(ret);
280 assert(address);
281 assert(hostname);
282
283 r = dns_name_reverse(family, address, &ptr);
284 if (r < 0)
285 return r;
286
287 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
288 if (!key)
289 return -ENOMEM;
290
291 ptr = NULL;
292
293 rr = dns_resource_record_new(key);
294 if (!rr)
295 return -ENOMEM;
296
297 rr->ptr.name = strdup(hostname);
298 if (!rr->ptr.name)
299 return -ENOMEM;
300
301 *ret = rr;
302 rr = NULL;
303
304 return 0;
305}
306
322345fd
LP
307int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
308 int r;
309
310 assert(a);
311 assert(b);
312
faa133f3 313 r = dns_resource_key_equal(a->key, b->key);
322345fd
LP
314 if (r <= 0)
315 return r;
316
2d4c5cbc
LP
317 switch (a->key->type) {
318
319 case DNS_TYPE_PTR:
320 case DNS_TYPE_NS:
321 case DNS_TYPE_CNAME:
322345fd 322 return dns_name_equal(a->ptr.name, b->ptr.name);
2d4c5cbc
LP
323
324 case DNS_TYPE_HINFO:
325 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
326 strcaseeq(a->hinfo.os, b->hinfo.os);
327
9de3e329 328 case DNS_TYPE_SPF: /* exactly the same as TXT */
2e276efc
ZJS
329 case DNS_TYPE_TXT: {
330 int i;
331
332 for (i = 0; a->txt.strings[i] || b->txt.strings[i]; i++)
333 if (!streq_ptr(a->txt.strings[i], b->txt.strings[i]))
334 return false;
335 return true;
336 }
337
2d4c5cbc 338 case DNS_TYPE_A:
322345fd 339 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
2d4c5cbc
LP
340
341 case DNS_TYPE_AAAA:
322345fd 342 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
2d4c5cbc
LP
343
344 case DNS_TYPE_SOA:
7e8e0422
LP
345 r = dns_name_equal(a->soa.mname, b->soa.mname);
346 if (r <= 0)
347 return r;
348 r = dns_name_equal(a->soa.rname, b->soa.rname);
349 if (r <= 0)
350 return r;
351
352 return a->soa.serial == b->soa.serial &&
353 a->soa.refresh == b->soa.refresh &&
354 a->soa.retry == b->soa.retry &&
355 a->soa.expire == b->soa.expire &&
356 a->soa.minimum == b->soa.minimum;
946c7094
ZJS
357 case DNS_TYPE_MX:
358 if (a->mx.priority != b->mx.priority)
359 return 0;
360
361 return dns_name_equal(a->mx.exchange, b->mx.exchange);
362
0dae31d4
ZJS
363 case DNS_TYPE_LOC:
364 assert(a->loc.version == b->loc.version);
365
366 return a->loc.size == b->loc.size &&
367 a->loc.horiz_pre == b->loc.horiz_pre &&
368 a->loc.vert_pre == b->loc.vert_pre &&
369 a->loc.latitude == b->loc.latitude &&
370 a->loc.longitude == b->loc.longitude &&
371 a->loc.altitude == b->loc.altitude;
372
2d4c5cbc 373 default:
322345fd
LP
374 return a->generic.size == b->generic.size &&
375 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
2d4c5cbc 376 }
322345fd
LP
377}
378
0dae31d4
ZJS
379static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
380 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
381 char *s;
382 char NS = latitude >= 1U<<31 ? 'N' : 'S';
383 char EW = longitude >= 1U<<31 ? 'E' : 'W';
384
385 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
386 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
387 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
388 double siz = (size >> 4) * exp10((double) (size & 0xF));
389 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
390 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
391
392 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
393 (lat / 60000 / 60),
394 (lat / 60000) % 60,
395 (lat % 60000) / 1000.,
396 NS,
397 (lon / 60000 / 60),
398 (lon / 60000) % 60,
399 (lon % 60000) / 1000.,
400 EW,
401 alt / 100.,
402 siz / 100.,
403 hor / 100.,
404 ver / 100.) < 0)
405 return NULL;
406
407 return s;
408}
409
410
2d4c5cbc
LP
411int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
412 _cleanup_free_ char *k = NULL;
413 char *s;
414 int r;
322345fd 415
2d4c5cbc 416 assert(rr);
322345fd 417
2d4c5cbc
LP
418 r = dns_resource_key_to_string(rr->key, &k);
419 if (r < 0)
420 return r;
322345fd 421
0dae31d4 422 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
322345fd 423
2d4c5cbc
LP
424 case DNS_TYPE_PTR:
425 case DNS_TYPE_NS:
426 case DNS_TYPE_CNAME:
427 s = strjoin(k, " ", rr->ptr.name, NULL);
428 if (!s)
429 return -ENOMEM;
322345fd 430
2d4c5cbc 431 break;
322345fd 432
2d4c5cbc
LP
433 case DNS_TYPE_HINFO:
434 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
435 if (!s)
436 return -ENOMEM;
437 break;
322345fd 438
9de3e329 439 case DNS_TYPE_SPF: /* exactly the same as TXT */
2e276efc
ZJS
440 case DNS_TYPE_TXT: {
441 _cleanup_free_ char *t;
442
443 t = strv_join_quoted(rr->txt.strings);
444 if (!t)
445 return -ENOMEM;
446
447 s = strjoin(k, " ", t, NULL);
448 if (!s)
449 return -ENOMEM;
450
451 break;
452 }
453
2d4c5cbc
LP
454 case DNS_TYPE_A: {
455 _cleanup_free_ char *x = NULL;
322345fd 456
2d4c5cbc
LP
457 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
458 if (r < 0)
459 return r;
322345fd 460
2d4c5cbc
LP
461 s = strjoin(k, " ", x, NULL);
462 if (!s)
463 return -ENOMEM;
464 break;
465 }
322345fd 466
2d4c5cbc
LP
467 case DNS_TYPE_AAAA: {
468 _cleanup_free_ char *x = NULL;
322345fd 469
2d4c5cbc
LP
470 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &x);
471 if (r < 0)
472 return r;
322345fd 473
2d4c5cbc
LP
474 s = strjoin(k, " ", x, NULL);
475 if (!s)
476 return -ENOMEM;
477 break;
478 }
322345fd 479
2d4c5cbc
LP
480 case DNS_TYPE_SOA:
481 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
482 k,
483 strna(rr->soa.mname),
484 strna(rr->soa.rname),
485 rr->soa.serial,
486 rr->soa.refresh,
487 rr->soa.retry,
488 rr->soa.expire,
489 rr->soa.minimum);
490 if (r < 0)
491 return -ENOMEM;
492 break;
493
946c7094
ZJS
494 case DNS_TYPE_MX:
495 r = asprintf(&s, "%s %u %s",
496 k,
497 rr->mx.priority,
498 rr->mx.exchange);
499 if (r < 0)
500 return -ENOMEM;
501 break;
502
0dae31d4
ZJS
503 case DNS_TYPE_LOC: {
504 _cleanup_free_ char *loc;
505 assert(rr->loc.version == 0);
506
507 loc = format_location(rr->loc.latitude,
508 rr->loc.longitude,
509 rr->loc.altitude,
510 rr->loc.size,
511 rr->loc.horiz_pre,
512 rr->loc.vert_pre);
513 if (!loc)
514 return -ENOMEM;
515
516 s = strjoin(k, " ", loc, NULL);
517 if (!s)
518 return -ENOMEM;
519
520 break;
521 }
522
2d4c5cbc
LP
523 default: {
524 _cleanup_free_ char *x = NULL;
525
526 x = hexmem(rr->generic.data, rr->generic.size);
527 if (!x)
528 return -ENOMEM;
529
530 s = strjoin(k, " ", x, NULL);
531 if (!s)
532 return -ENOMEM;
533 break;
534 }}
535
536 *ret = s;
537 return 0;
538}
322345fd 539
2d4c5cbc 540const char *dns_class_to_string(uint16_t class) {
322345fd 541
2d4c5cbc 542 switch (class) {
322345fd 543
2d4c5cbc
LP
544 case DNS_CLASS_IN:
545 return "IN";
322345fd 546
2d4c5cbc
LP
547 case DNS_CLASS_ANY:
548 return "ANY";
549 }
322345fd 550
2d4c5cbc
LP
551 return NULL;
552}
322345fd 553
2d4c5cbc
LP
554int dns_class_from_string(const char *s, uint16_t *class) {
555 assert(s);
556 assert(class);
557
558 if (strcaseeq(s, "IN"))
559 *class = DNS_CLASS_IN;
560 else if (strcaseeq(s, "ANY"))
561 *class = DNS_TYPE_ANY;
562 else
563 return -EINVAL;
322345fd 564
2d4c5cbc
LP
565 return 0;
566}
322345fd 567
2d4c5cbc
LP
568static const struct {
569 uint16_t type;
570 const char *name;
571} dns_types[] = {
572 { DNS_TYPE_A, "A" },
573 { DNS_TYPE_NS, "NS" },
574 { DNS_TYPE_CNAME, "CNAME" },
575 { DNS_TYPE_SOA, "SOA" },
576 { DNS_TYPE_PTR, "PTR" },
577 { DNS_TYPE_HINFO, "HINFO" },
578 { DNS_TYPE_MX, "MX" },
579 { DNS_TYPE_TXT, "TXT" },
580 { DNS_TYPE_AAAA, "AAAA" },
0dae31d4 581 { DNS_TYPE_LOC, "LOC" },
2d4c5cbc
LP
582 { DNS_TYPE_SRV, "SRV" },
583 { DNS_TYPE_SSHFP, "SSHFP" },
9de3e329 584 { DNS_TYPE_SPF, "SPF" },
2d4c5cbc
LP
585 { DNS_TYPE_DNAME, "DNAME" },
586 { DNS_TYPE_ANY, "ANY" },
587 { DNS_TYPE_OPT, "OPT" },
588 { DNS_TYPE_TKEY, "TKEY" },
589 { DNS_TYPE_TSIG, "TSIG" },
590 { DNS_TYPE_IXFR, "IXFR" },
591 { DNS_TYPE_AXFR, "AXFR" },
592};
322345fd 593
322345fd 594
2d4c5cbc
LP
595const char *dns_type_to_string(uint16_t type) {
596 unsigned i;
322345fd 597
2d4c5cbc
LP
598 for (i = 0; i < ELEMENTSOF(dns_types); i++)
599 if (dns_types[i].type == type)
600 return dns_types[i].name;
322345fd
LP
601
602 return NULL;
603}
2d4c5cbc
LP
604
605int dns_type_from_string(const char *s, uint16_t *type) {
606 unsigned i;
607
608 assert(s);
609 assert(type);
610
611 for (i = 0; i < ELEMENTSOF(dns_types); i++)
612 if (strcaseeq(dns_types[i].name, s)) {
613 *type = dns_types[i].type;
614 return 0;
615 }
616
617 return -EINVAL;
618}