]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-rr.c
resolved: don't bother with picking a search domain when searching is disabled
[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
b5efdb8a 24#include "alloc-util.h"
4ad7f276 25#include "dns-domain.h"
7263f724 26#include "dns-type.h"
e4e73a63 27#include "hexdecoct.h"
07630cea 28#include "resolved-dns-packet.h"
e4e73a63 29#include "resolved-dns-rr.h"
8730bccf 30#include "string-table.h"
07630cea
LP
31#include "string-util.h"
32#include "strv.h"
74b2466e 33
faa133f3
LP
34DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
35 DnsResourceKey *k;
36 size_t l;
74b2466e 37
faa133f3
LP
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
36d9205d 54DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) {
58db254a
LP
55 int r;
56
36d9205d
TG
57 assert(key);
58 assert(cname);
59
58db254a
LP
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 }
36d9205d
TG
82}
83
801ad6a6
LP
84int 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
dc477e73 93 if (dns_name_is_root(name)) {
801ad6a6
LP
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
faa133f3
LP
112DnsResourceKey* 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
129DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
130
131 if (!k)
132 return NULL;
133
1b4f6e79
LP
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
faa133f3
LP
138 assert(k->n_ref > 0);
139 k->n_ref++;
140
141 return k;
142}
143
144DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
145 if (!k)
146 return NULL;
147
1b4f6e79 148 assert(k->n_ref != (unsigned) -1);
faa133f3
LP
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
160int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
161 int r;
162
163 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
164 if (r <= 0)
165 return r;
166
167 if (a->class != b->class)
168 return 0;
169
170 if (a->type != b->type)
171 return 0;
172
173 return 1;
174}
175
801ad6a6
LP
176int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain) {
177 int r;
178
faa133f3
LP
179 assert(key);
180 assert(rr);
181
801ad6a6
LP
182 /* Checks if an rr matches the specified key. If a search
183 * domain is specified, it will also be checked if the key
184 * with the search domain suffixed might match the RR. */
185
faa133f3
LP
186 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
187 return 0;
188
189 if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
190 return 0;
191
801ad6a6
LP
192 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
193 if (r != 0)
194 return r;
195
196 if (search_domain) {
197 _cleanup_free_ char *joined = NULL;
198
199 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
200 if (r < 0)
201 return r;
202
203 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), joined);
204 }
205
206 return 0;
faa133f3
LP
207}
208
801ad6a6
LP
209int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain) {
210 int r;
211
faa133f3
LP
212 assert(key);
213 assert(rr);
214
215 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
216 return 0;
217
58db254a 218 if (rr->key->type == DNS_TYPE_CNAME)
801ad6a6 219 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(rr->key));
58db254a 220 else if (rr->key->type == DNS_TYPE_DNAME)
801ad6a6 221 r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(rr->key));
58db254a 222 else
faa133f3 223 return 0;
801ad6a6
LP
224
225 if (r != 0)
226 return r;
227
228 if (search_domain) {
229 _cleanup_free_ char *joined = NULL;
230
231 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
232 if (r < 0)
233 return r;
234
235 if (rr->key->type == DNS_TYPE_CNAME)
236 return dns_name_equal(joined, DNS_RESOURCE_KEY_NAME(rr->key));
237 else if (rr->key->type == DNS_TYPE_DNAME)
238 return dns_name_endswith(joined, DNS_RESOURCE_KEY_NAME(rr->key));
239 }
240
241 return 0;
242
74b2466e
LP
243}
244
b826ab58 245static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
322345fd 246 const DnsResourceKey *k = i;
322345fd 247
b826ab58 248 assert(k);
322345fd 249
b826ab58
TG
250 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state);
251 siphash24_compress(&k->class, sizeof(k->class), state);
252 siphash24_compress(&k->type, sizeof(k->type), state);
322345fd
LP
253}
254
d5099efc 255static int dns_resource_key_compare_func(const void *a, const void *b) {
322345fd
LP
256 const DnsResourceKey *x = a, *y = b;
257 int ret;
258
faa133f3 259 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
322345fd
LP
260 if (ret != 0)
261 return ret;
262
263 if (x->type < y->type)
264 return -1;
265 if (x->type > y->type)
266 return 1;
267
268 if (x->class < y->class)
269 return -1;
270 if (x->class > y->class)
271 return 1;
272
273 return 0;
274}
275
d5099efc
MS
276const struct hash_ops dns_resource_key_hash_ops = {
277 .hash = dns_resource_key_hash_func,
278 .compare = dns_resource_key_compare_func
279};
280
2d4c5cbc 281int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
d23a27a9 282 char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
2d4c5cbc
LP
283 const char *c, *t;
284 char *s;
285
286 c = dns_class_to_string(key->class);
287 if (!c) {
d23a27a9 288 sprintf(cbuf, "CLASS%u", key->class);
2d4c5cbc
LP
289 c = cbuf;
290 }
291
292 t = dns_type_to_string(key->type);
293 if (!t){
d23a27a9 294 sprintf(tbuf, "TYPE%u", key->type);
2d4c5cbc
LP
295 t = tbuf;
296 }
297
23432a1c 298 if (asprintf(&s, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key), c, t) < 0)
2d4c5cbc
LP
299 return -ENOMEM;
300
301 *ret = s;
302 return 0;
303}
304
faa133f3 305DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
74b2466e
LP
306 DnsResourceRecord *rr;
307
308 rr = new0(DnsResourceRecord, 1);
309 if (!rr)
310 return NULL;
311
312 rr->n_ref = 1;
faa133f3
LP
313 rr->key = dns_resource_key_ref(key);
314
74b2466e
LP
315 return rr;
316}
317
8bf52d3d
LP
318DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
319 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
320
321 key = dns_resource_key_new(class, type, name);
322 if (!key)
323 return NULL;
324
325 return dns_resource_record_new(key);
326}
327
74b2466e
LP
328DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
329 if (!rr)
330 return NULL;
331
332 assert(rr->n_ref > 0);
333 rr->n_ref++;
334
335 return rr;
336}
337
338DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
339 if (!rr)
340 return NULL;
341
342 assert(rr->n_ref > 0);
343
344 if (rr->n_ref > 1) {
345 rr->n_ref--;
346 return NULL;
347 }
348
faa133f3 349 if (rr->key) {
9de3e329 350 switch(rr->key->type) {
9c92ce6d
LP
351
352 case DNS_TYPE_SRV:
353 free(rr->srv.name);
354 break;
355
9de3e329
ZJS
356 case DNS_TYPE_PTR:
357 case DNS_TYPE_NS:
358 case DNS_TYPE_CNAME:
8ac4e9e1 359 case DNS_TYPE_DNAME:
faa133f3 360 free(rr->ptr.name);
9de3e329 361 break;
9c92ce6d 362
9de3e329 363 case DNS_TYPE_HINFO:
faa133f3
LP
364 free(rr->hinfo.cpu);
365 free(rr->hinfo.os);
9de3e329 366 break;
9c92ce6d 367
9de3e329 368 case DNS_TYPE_TXT:
9c92ce6d 369 case DNS_TYPE_SPF:
2001c805 370 dns_txt_item_free_all(rr->txt.items);
9de3e329 371 break;
9c92ce6d 372
9de3e329 373 case DNS_TYPE_SOA:
7e8e0422
LP
374 free(rr->soa.mname);
375 free(rr->soa.rname);
9de3e329 376 break;
9c92ce6d 377
9de3e329 378 case DNS_TYPE_MX:
946c7094 379 free(rr->mx.exchange);
9de3e329 380 break;
9c92ce6d 381
abf126a3
TG
382 case DNS_TYPE_DS:
383 free(rr->ds.digest);
384 break;
385
42cc2eeb 386 case DNS_TYPE_SSHFP:
549c1a25 387 free(rr->sshfp.fingerprint);
42cc2eeb
LP
388 break;
389
8db0d2f5
ZJS
390 case DNS_TYPE_DNSKEY:
391 free(rr->dnskey.key);
392 break;
393
151226ab
ZJS
394 case DNS_TYPE_RRSIG:
395 free(rr->rrsig.signer);
396 free(rr->rrsig.signature);
397 break;
398
50f1e641
TG
399 case DNS_TYPE_NSEC:
400 free(rr->nsec.next_domain_name);
401 bitmap_free(rr->nsec.types);
402 break;
403
5d45a880
TG
404 case DNS_TYPE_NSEC3:
405 free(rr->nsec3.next_hashed_name);
406 free(rr->nsec3.salt);
407 bitmap_free(rr->nsec3.types);
408 break;
409
0dae31d4 410 case DNS_TYPE_LOC:
9de3e329
ZJS
411 case DNS_TYPE_A:
412 case DNS_TYPE_AAAA:
413 break;
9c92ce6d 414
9de3e329 415 default:
faa133f3 416 free(rr->generic.data);
9de3e329 417 }
322345fd 418
a8812dd7 419 free(rr->wire_format);
faa133f3
LP
420 dns_resource_key_unref(rr->key);
421 }
322345fd 422
faa133f3 423 free(rr);
322345fd 424
322345fd
LP
425 return NULL;
426}
427
623a4c97
LP
428int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
429 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
430 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
431 _cleanup_free_ char *ptr = NULL;
432 int r;
433
434 assert(ret);
435 assert(address);
436 assert(hostname);
437
438 r = dns_name_reverse(family, address, &ptr);
439 if (r < 0)
440 return r;
441
442 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
443 if (!key)
444 return -ENOMEM;
445
446 ptr = NULL;
447
448 rr = dns_resource_record_new(key);
449 if (!rr)
450 return -ENOMEM;
451
452 rr->ptr.name = strdup(hostname);
453 if (!rr->ptr.name)
454 return -ENOMEM;
455
456 *ret = rr;
457 rr = NULL;
458
459 return 0;
460}
461
78c6a153
LP
462int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
463 DnsResourceRecord *rr;
464
465 assert(ret);
466 assert(address);
467 assert(family);
468
469 if (family == AF_INET) {
470
471 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
472 if (!rr)
473 return -ENOMEM;
474
475 rr->a.in_addr = address->in;
476
477 } else if (family == AF_INET6) {
478
479 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
480 if (!rr)
481 return -ENOMEM;
482
483 rr->aaaa.in6_addr = address->in6;
484 } else
485 return -EAFNOSUPPORT;
486
487 *ret = rr;
488
489 return 0;
490}
491
322345fd
LP
492int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
493 int r;
494
495 assert(a);
496 assert(b);
497
faa133f3 498 r = dns_resource_key_equal(a->key, b->key);
322345fd
LP
499 if (r <= 0)
500 return r;
501
fd0b4602
LP
502 if (a->unparseable != b->unparseable)
503 return 0;
504
505 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
2d4c5cbc 506
9c92ce6d
LP
507 case DNS_TYPE_SRV:
508 r = dns_name_equal(a->srv.name, b->srv.name);
509 if (r <= 0)
510 return r;
511
512 return a->srv.priority == b->srv.priority &&
513 a->srv.weight == b->srv.weight &&
514 a->srv.port == b->srv.port;
515
2d4c5cbc
LP
516 case DNS_TYPE_PTR:
517 case DNS_TYPE_NS:
518 case DNS_TYPE_CNAME:
8ac4e9e1 519 case DNS_TYPE_DNAME:
322345fd 520 return dns_name_equal(a->ptr.name, b->ptr.name);
2d4c5cbc
LP
521
522 case DNS_TYPE_HINFO:
523 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
524 strcaseeq(a->hinfo.os, b->hinfo.os);
525
9de3e329 526 case DNS_TYPE_SPF: /* exactly the same as TXT */
0f84a72e 527 case DNS_TYPE_TXT:
2001c805 528 return dns_txt_item_equal(a->txt.items, b->txt.items);
2e276efc 529
2d4c5cbc 530 case DNS_TYPE_A:
322345fd 531 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
2d4c5cbc
LP
532
533 case DNS_TYPE_AAAA:
322345fd 534 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
2d4c5cbc
LP
535
536 case DNS_TYPE_SOA:
7e8e0422
LP
537 r = dns_name_equal(a->soa.mname, b->soa.mname);
538 if (r <= 0)
539 return r;
540 r = dns_name_equal(a->soa.rname, b->soa.rname);
541 if (r <= 0)
542 return r;
543
544 return a->soa.serial == b->soa.serial &&
545 a->soa.refresh == b->soa.refresh &&
546 a->soa.retry == b->soa.retry &&
547 a->soa.expire == b->soa.expire &&
548 a->soa.minimum == b->soa.minimum;
9c92ce6d 549
946c7094
ZJS
550 case DNS_TYPE_MX:
551 if (a->mx.priority != b->mx.priority)
552 return 0;
553
554 return dns_name_equal(a->mx.exchange, b->mx.exchange);
555
0dae31d4
ZJS
556 case DNS_TYPE_LOC:
557 assert(a->loc.version == b->loc.version);
558
559 return a->loc.size == b->loc.size &&
560 a->loc.horiz_pre == b->loc.horiz_pre &&
561 a->loc.vert_pre == b->loc.vert_pre &&
562 a->loc.latitude == b->loc.latitude &&
563 a->loc.longitude == b->loc.longitude &&
564 a->loc.altitude == b->loc.altitude;
565
abf126a3
TG
566 case DNS_TYPE_DS:
567 return a->ds.key_tag == b->ds.key_tag &&
568 a->ds.algorithm == b->ds.algorithm &&
569 a->ds.digest_type == b->ds.digest_type &&
570 a->ds.digest_size == b->ds.digest_size &&
571 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
572
42cc2eeb
LP
573 case DNS_TYPE_SSHFP:
574 return a->sshfp.algorithm == b->sshfp.algorithm &&
575 a->sshfp.fptype == b->sshfp.fptype &&
549c1a25
TG
576 a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
577 memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
42cc2eeb 578
8db0d2f5 579 case DNS_TYPE_DNSKEY:
f91dc240
LP
580 return a->dnskey.flags == b->dnskey.flags &&
581 a->dnskey.protocol == b->dnskey.protocol &&
8db0d2f5
ZJS
582 a->dnskey.algorithm == b->dnskey.algorithm &&
583 a->dnskey.key_size == b->dnskey.key_size &&
584 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
585
151226ab
ZJS
586 case DNS_TYPE_RRSIG:
587 /* do the fast comparisons first */
03664a62
LN
588 if (a->rrsig.type_covered != b->rrsig.type_covered ||
589 a->rrsig.algorithm != b->rrsig.algorithm ||
590 a->rrsig.labels != b->rrsig.labels ||
591 a->rrsig.original_ttl != b->rrsig.original_ttl ||
592 a->rrsig.expiration != b->rrsig.expiration ||
593 a->rrsig.inception != b->rrsig.inception ||
594 a->rrsig.key_tag != b->rrsig.key_tag ||
151226ab
ZJS
595 a->rrsig.signature_size != b->rrsig.signature_size ||
596 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
597 return false;
598
599 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
600
50f1e641
TG
601 case DNS_TYPE_NSEC:
602 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
603 bitmap_equal(a->nsec.types, b->nsec.types);
604
5d45a880
TG
605 case DNS_TYPE_NSEC3:
606 return a->nsec3.algorithm == b->nsec3.algorithm &&
607 a->nsec3.flags == b->nsec3.flags &&
608 a->nsec3.iterations == b->nsec3.iterations &&
609 a->nsec3.salt_size == b->nsec3.salt_size &&
610 memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
611 memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
612 bitmap_equal(a->nsec3.types, b->nsec3.types);
613
2d4c5cbc 614 default:
322345fd
LP
615 return a->generic.size == b->generic.size &&
616 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
2d4c5cbc 617 }
322345fd
LP
618}
619
0dae31d4
ZJS
620static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
621 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
622 char *s;
623 char NS = latitude >= 1U<<31 ? 'N' : 'S';
624 char EW = longitude >= 1U<<31 ? 'E' : 'W';
625
626 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
627 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
628 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
629 double siz = (size >> 4) * exp10((double) (size & 0xF));
630 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
631 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
632
633 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
634 (lat / 60000 / 60),
635 (lat / 60000) % 60,
636 (lat % 60000) / 1000.,
637 NS,
638 (lon / 60000 / 60),
639 (lon / 60000) % 60,
640 (lon % 60000) / 1000.,
641 EW,
642 alt / 100.,
643 siz / 100.,
644 hor / 100.,
645 ver / 100.) < 0)
646 return NULL;
647
648 return s;
649}
650
7c6423e1
TG
651static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
652 struct tm tm;
653
654 assert(buf);
655 assert(l > strlen("YYYYMMDDHHmmSS"));
656
657 if (!gmtime_r(&sec, &tm))
658 return -EINVAL;
659
660 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
661 return -EINVAL;
662
663 return 0;
664}
665
50f1e641
TG
666static char *format_types(Bitmap *types) {
667 _cleanup_strv_free_ char **strv = NULL;
668 _cleanup_free_ char *str = NULL;
cb57dd41 669 Iterator i;
50f1e641
TG
670 unsigned type;
671 int r;
672
cb57dd41 673 BITMAP_FOREACH(type, types, i) {
50f1e641 674 if (dns_type_to_string(type)) {
2c1fb4f7 675 r = strv_extend(&strv, dns_type_to_string(type));
50f1e641
TG
676 if (r < 0)
677 return NULL;
678 } else {
679 char *t;
680
681 r = asprintf(&t, "TYPE%u", type);
682 if (r < 0)
683 return NULL;
684
2c1fb4f7 685 r = strv_consume(&strv, t);
50f1e641
TG
686 if (r < 0)
687 return NULL;
688 }
689 }
690
691 str = strv_join(strv, " ");
692 if (!str)
693 return NULL;
694
695 return strjoin("( ", str, " )", NULL);
696}
697
2001c805
LP
698static char *format_txt(DnsTxtItem *first) {
699 DnsTxtItem *i;
700 size_t c = 1;
701 char *p, *s;
702
703 LIST_FOREACH(items, i, first)
704 c += i->length * 4 + 3;
705
706 p = s = new(char, c);
707 if (!s)
708 return NULL;
709
710 LIST_FOREACH(items, i, first) {
711 size_t j;
712
713 if (i != first)
714 *(p++) = ' ';
715
716 *(p++) = '"';
717
718 for (j = 0; j < i->length; j++) {
719 if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) {
720 *(p++) = '\\';
721 *(p++) = '0' + (i->data[j] / 100);
722 *(p++) = '0' + ((i->data[j] / 10) % 10);
723 *(p++) = '0' + (i->data[j] % 10);
724 } else
725 *(p++) = i->data[j];
726 }
727
728 *(p++) = '"';
729 }
730
731 *p = 0;
732 return s;
733}
734
2d4c5cbc 735int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
8db0d2f5 736 _cleanup_free_ char *k = NULL, *t = NULL;
2d4c5cbc
LP
737 char *s;
738 int r;
322345fd 739
2d4c5cbc 740 assert(rr);
322345fd 741
2d4c5cbc
LP
742 r = dns_resource_key_to_string(rr->key, &k);
743 if (r < 0)
744 return r;
322345fd 745
0dae31d4 746 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
322345fd 747
9c92ce6d
LP
748 case DNS_TYPE_SRV:
749 r = asprintf(&s, "%s %u %u %u %s",
750 k,
751 rr->srv.priority,
752 rr->srv.weight,
753 rr->srv.port,
754 strna(rr->srv.name));
755 if (r < 0)
756 return -ENOMEM;
757 break;
758
2d4c5cbc
LP
759 case DNS_TYPE_PTR:
760 case DNS_TYPE_NS:
761 case DNS_TYPE_CNAME:
8ac4e9e1 762 case DNS_TYPE_DNAME:
2d4c5cbc
LP
763 s = strjoin(k, " ", rr->ptr.name, NULL);
764 if (!s)
765 return -ENOMEM;
322345fd 766
2d4c5cbc 767 break;
322345fd 768
2d4c5cbc
LP
769 case DNS_TYPE_HINFO:
770 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
771 if (!s)
772 return -ENOMEM;
773 break;
322345fd 774
9de3e329 775 case DNS_TYPE_SPF: /* exactly the same as TXT */
8db0d2f5 776 case DNS_TYPE_TXT:
2001c805 777 t = format_txt(rr->txt.items);
2e276efc
ZJS
778 if (!t)
779 return -ENOMEM;
780
781 s = strjoin(k, " ", t, NULL);
782 if (!s)
783 return -ENOMEM;
2e276efc 784 break;
2e276efc 785
2d4c5cbc
LP
786 case DNS_TYPE_A: {
787 _cleanup_free_ char *x = NULL;
322345fd 788
2d4c5cbc
LP
789 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
790 if (r < 0)
791 return r;
322345fd 792
2d4c5cbc
LP
793 s = strjoin(k, " ", x, NULL);
794 if (!s)
795 return -ENOMEM;
796 break;
797 }
322345fd 798
8db0d2f5
ZJS
799 case DNS_TYPE_AAAA:
800 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
2d4c5cbc
LP
801 if (r < 0)
802 return r;
322345fd 803
8db0d2f5 804 s = strjoin(k, " ", t, NULL);
2d4c5cbc
LP
805 if (!s)
806 return -ENOMEM;
807 break;
322345fd 808
2d4c5cbc
LP
809 case DNS_TYPE_SOA:
810 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
811 k,
812 strna(rr->soa.mname),
813 strna(rr->soa.rname),
814 rr->soa.serial,
815 rr->soa.refresh,
816 rr->soa.retry,
817 rr->soa.expire,
818 rr->soa.minimum);
819 if (r < 0)
820 return -ENOMEM;
821 break;
822
946c7094
ZJS
823 case DNS_TYPE_MX:
824 r = asprintf(&s, "%s %u %s",
825 k,
826 rr->mx.priority,
827 rr->mx.exchange);
828 if (r < 0)
829 return -ENOMEM;
830 break;
831
8db0d2f5 832 case DNS_TYPE_LOC:
0dae31d4
ZJS
833 assert(rr->loc.version == 0);
834
8db0d2f5
ZJS
835 t = format_location(rr->loc.latitude,
836 rr->loc.longitude,
837 rr->loc.altitude,
838 rr->loc.size,
839 rr->loc.horiz_pre,
840 rr->loc.vert_pre);
841 if (!t)
0dae31d4
ZJS
842 return -ENOMEM;
843
8db0d2f5 844 s = strjoin(k, " ", t, NULL);
0dae31d4
ZJS
845 if (!s)
846 return -ENOMEM;
0dae31d4 847 break;
0dae31d4 848
abf126a3
TG
849 case DNS_TYPE_DS:
850 t = hexmem(rr->ds.digest, rr->ds.digest_size);
851 if (!t)
852 return -ENOMEM;
853
854 r = asprintf(&s, "%s %u %u %u %s",
855 k,
856 rr->ds.key_tag,
857 rr->ds.algorithm,
858 rr->ds.digest_type,
859 t);
860 if (r < 0)
861 return -ENOMEM;
862 break;
863
8db0d2f5 864 case DNS_TYPE_SSHFP:
549c1a25 865 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
8db0d2f5 866 if (!t)
42cc2eeb
LP
867 return -ENOMEM;
868
869 r = asprintf(&s, "%s %u %u %s",
870 k,
871 rr->sshfp.algorithm,
872 rr->sshfp.fptype,
8db0d2f5 873 t);
42cc2eeb
LP
874 if (r < 0)
875 return -ENOMEM;
876 break;
42cc2eeb 877
ff3d6560
ZJS
878 case DNS_TYPE_DNSKEY: {
879 const char *alg;
880
881 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
882
1bf968f3 883 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
8db0d2f5
ZJS
884 if (!t)
885 return -ENOMEM;
2d4c5cbc 886
f91dc240 887 r = asprintf(&s, "%s %u %u %.*s%.*u %s",
8db0d2f5 888 k,
f91dc240
LP
889 rr->dnskey.flags,
890 rr->dnskey.protocol,
ff3d6560
ZJS
891 alg ? -1 : 0, alg,
892 alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
8db0d2f5
ZJS
893 t);
894 if (r < 0)
2d4c5cbc 895 return -ENOMEM;
8db0d2f5 896 break;
ff3d6560 897 }
2d4c5cbc 898
151226ab
ZJS
899 case DNS_TYPE_RRSIG: {
900 const char *type, *alg;
7c6423e1 901 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
151226ab
ZJS
902
903 type = dns_type_to_string(rr->rrsig.type_covered);
904 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
905
1bf968f3 906 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
151226ab
ZJS
907 if (!t)
908 return -ENOMEM;
909
7c6423e1
TG
910 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
911 if (r < 0)
912 return r;
913
914 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
915 if (r < 0)
916 return r;
917
151226ab
ZJS
918 /* TYPE?? follows
919 * http://tools.ietf.org/html/rfc3597#section-5 */
920
7c6423e1 921 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
151226ab
ZJS
922 k,
923 type ?: "TYPE",
924 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
925 alg ? -1 : 0, alg,
926 alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
927 rr->rrsig.labels,
928 rr->rrsig.original_ttl,
7c6423e1
TG
929 expiration,
930 inception,
151226ab
ZJS
931 rr->rrsig.key_tag,
932 rr->rrsig.signer,
933 t);
934 if (r < 0)
935 return -ENOMEM;
936 break;
937 }
938
50f1e641
TG
939 case DNS_TYPE_NSEC:
940 t = format_types(rr->nsec.types);
941 if (!t)
942 return -ENOMEM;
943
944 r = asprintf(&s, "%s %s %s",
945 k,
946 rr->nsec.next_domain_name,
947 t);
948 if (r < 0)
949 return -ENOMEM;
950 break;
951
5d45a880
TG
952 case DNS_TYPE_NSEC3: {
953 _cleanup_free_ char *salt = NULL, *hash = NULL;
954
f5430a3e 955 if (rr->nsec3.salt_size > 0) {
5d45a880
TG
956 salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
957 if (!salt)
958 return -ENOMEM;
959 }
960
961 hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
962 if (!hash)
963 return -ENOMEM;
964
965 t = format_types(rr->nsec3.types);
966 if (!t)
967 return -ENOMEM;
968
969 r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
970 k,
971 rr->nsec3.algorithm,
972 rr->nsec3.flags,
973 rr->nsec3.iterations,
f5430a3e 974 rr->nsec3.salt_size > 0 ? salt : "-",
5d45a880
TG
975 hash,
976 t);
977 if (r < 0)
978 return -ENOMEM;
979
980 break;
981 }
982
8db0d2f5
ZJS
983 default:
984 t = hexmem(rr->generic.data, rr->generic.size);
985 if (!t)
986 return -ENOMEM;
987
f5430a3e 988 r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
d23a27a9 989 if (r < 0)
2d4c5cbc
LP
990 return -ENOMEM;
991 break;
8db0d2f5 992 }
2d4c5cbc
LP
993
994 *ret = s;
995 return 0;
996}
322345fd 997
a8812dd7
LP
998int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {
999
1000 DnsPacket packet = {
1001 .n_ref = 1,
1002 .protocol = DNS_PROTOCOL_DNS,
1003 .on_stack = true,
1004 .refuse_compression = true,
1005 .canonical_form = canonical,
1006 };
1007
1008 size_t start, rds;
1009 int r;
1010
1011 assert(rr);
1012
1013 /* Generates the RR in wire-format, optionally in the
1014 * canonical form as discussed in the DNSSEC RFC 4034, Section
1015 * 6.2. We allocate a throw-away DnsPacket object on the stack
1016 * here, because we need some book-keeping for memory
1017 * management, and can reuse the DnsPacket serializer, that
1018 * can generate the canonical form, too, but also knows label
1019 * compression and suchlike. */
1020
1021 if (rr->wire_format && rr->wire_format_canonical == canonical)
1022 return 0;
1023
1024 r = dns_packet_append_rr(&packet, rr, &start, &rds);
1025 if (r < 0)
1026 return r;
1027
1028 assert(start == 0);
1029 assert(packet._data);
1030
1031 free(rr->wire_format);
1032 rr->wire_format = packet._data;
1033 rr->wire_format_size = packet.size;
1034 rr->wire_format_rdata_offset = rds;
1035 rr->wire_format_canonical = canonical;
1036
1037 packet._data = NULL;
1038 dns_packet_unref(&packet);
1039
1040 return 0;
1041}
1042
2d4c5cbc 1043const char *dns_class_to_string(uint16_t class) {
322345fd 1044
2d4c5cbc 1045 switch (class) {
322345fd 1046
2d4c5cbc
LP
1047 case DNS_CLASS_IN:
1048 return "IN";
322345fd 1049
2d4c5cbc
LP
1050 case DNS_CLASS_ANY:
1051 return "ANY";
1052 }
322345fd 1053
2d4c5cbc
LP
1054 return NULL;
1055}
322345fd 1056
2d4c5cbc
LP
1057int dns_class_from_string(const char *s, uint16_t *class) {
1058 assert(s);
1059 assert(class);
1060
1061 if (strcaseeq(s, "IN"))
1062 *class = DNS_CLASS_IN;
1063 else if (strcaseeq(s, "ANY"))
816b4547 1064 *class = DNS_CLASS_ANY;
2d4c5cbc
LP
1065 else
1066 return -EINVAL;
322345fd 1067
2d4c5cbc
LP
1068 return 0;
1069}
2001c805
LP
1070
1071DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
1072 DnsTxtItem *n;
1073
1074 if (!i)
1075 return NULL;
1076
1077 n = i->items_next;
1078
1079 free(i);
1080 return dns_txt_item_free_all(n);
1081}
1082
1083bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
1084
1085 if (!a != !b)
1086 return false;
1087
1088 if (!a)
1089 return true;
1090
1091 if (a->length != b->length)
1092 return false;
1093
1094 if (memcmp(a->data, b->data, a->length) != 0)
1095 return false;
1096
1097 return dns_txt_item_equal(a->items_next, b->items_next);
1098}
8730bccf
LP
1099
1100static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
1101 [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
1102 [DNSSEC_ALGORITHM_DH] = "DH",
1103 [DNSSEC_ALGORITHM_DSA] = "DSA",
1104 [DNSSEC_ALGORITHM_ECC] = "ECC",
1105 [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
1106 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1",
1107 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1",
1108 [DNSSEC_ALGORITHM_RSASHA256] = "RSASHA256",
1109 [DNSSEC_ALGORITHM_RSASHA512] = "RSASHA512",
1110 [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
1111 [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
1112 [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
1113};
1114DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int);
1115
1116static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = {
1117 [DNSSEC_DIGEST_SHA1] = "SHA1",
1118 [DNSSEC_DIGEST_SHA256] = "SHA256",
1119};
1120DEFINE_STRING_TABLE_LOOKUP(dnssec_digest, int);