question: drop dns_question_is_superset() which we don't use anymore
[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"
07630cea
LP
30#include "string-util.h"
31#include "strv.h"
74b2466e 32
faa133f3
LP
33DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
34 DnsResourceKey *k;
35 size_t l;
74b2466e 36
faa133f3
LP
37 assert(name);
38
39 l = strlen(name);
40 k = malloc0(sizeof(DnsResourceKey) + l + 1);
41 if (!k)
42 return NULL;
43
44 k->n_ref = 1;
45 k->class = class;
46 k->type = type;
47
48 strcpy((char*) k + sizeof(DnsResourceKey), name);
49
50 return k;
51}
52
7c1ff6ac
TG
53DnsResourceKey* dns_resource_key_new_cname(const DnsResourceKey *key) {
54 assert(key);
55
56 return dns_resource_key_new(key->class, DNS_TYPE_CNAME, DNS_RESOURCE_KEY_NAME(key));
57}
58
36d9205d
TG
59DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) {
60 assert(key);
61 assert(cname);
62
63 return dns_resource_key_new(key->class, key->type, cname->cname.name);
64}
65
faa133f3
LP
66DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
67 DnsResourceKey *k;
68
69 assert(name);
70
71 k = new0(DnsResourceKey, 1);
72 if (!k)
73 return NULL;
74
75 k->n_ref = 1;
76 k->class = class;
77 k->type = type;
78 k->_name = name;
79
80 return k;
81}
82
83DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
84
85 if (!k)
86 return NULL;
87
88 assert(k->n_ref > 0);
89 k->n_ref++;
90
91 return k;
92}
93
94DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
95 if (!k)
96 return NULL;
97
98 assert(k->n_ref > 0);
99
100 if (k->n_ref == 1) {
101 free(k->_name);
102 free(k);
103 } else
104 k->n_ref--;
105
106 return NULL;
107}
108
109int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
110 int r;
111
112 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
113 if (r <= 0)
114 return r;
115
116 if (a->class != b->class)
117 return 0;
118
119 if (a->type != b->type)
120 return 0;
121
122 return 1;
123}
124
125int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr) {
126 assert(key);
127 assert(rr);
128
129 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
130 return 0;
131
132 if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
133 return 0;
134
135 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
136}
137
138int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr) {
139 assert(key);
140 assert(rr);
141
142 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
143 return 0;
144
145 if (rr->key->type != DNS_TYPE_CNAME)
146 return 0;
147
148 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
74b2466e
LP
149}
150
b826ab58 151static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
322345fd 152 const DnsResourceKey *k = i;
322345fd 153
b826ab58 154 assert(k);
322345fd 155
b826ab58
TG
156 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state);
157 siphash24_compress(&k->class, sizeof(k->class), state);
158 siphash24_compress(&k->type, sizeof(k->type), state);
322345fd
LP
159}
160
d5099efc 161static int dns_resource_key_compare_func(const void *a, const void *b) {
322345fd
LP
162 const DnsResourceKey *x = a, *y = b;
163 int ret;
164
faa133f3 165 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
322345fd
LP
166 if (ret != 0)
167 return ret;
168
169 if (x->type < y->type)
170 return -1;
171 if (x->type > y->type)
172 return 1;
173
174 if (x->class < y->class)
175 return -1;
176 if (x->class > y->class)
177 return 1;
178
179 return 0;
180}
181
d5099efc
MS
182const struct hash_ops dns_resource_key_hash_ops = {
183 .hash = dns_resource_key_hash_func,
184 .compare = dns_resource_key_compare_func
185};
186
2d4c5cbc 187int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
d23a27a9 188 char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
2d4c5cbc
LP
189 const char *c, *t;
190 char *s;
191
192 c = dns_class_to_string(key->class);
193 if (!c) {
d23a27a9 194 sprintf(cbuf, "CLASS%u", key->class);
2d4c5cbc
LP
195 c = cbuf;
196 }
197
198 t = dns_type_to_string(key->type);
199 if (!t){
d23a27a9 200 sprintf(tbuf, "TYPE%u", key->type);
2d4c5cbc
LP
201 t = tbuf;
202 }
203
23432a1c 204 if (asprintf(&s, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key), c, t) < 0)
2d4c5cbc
LP
205 return -ENOMEM;
206
207 *ret = s;
208 return 0;
209}
210
faa133f3 211DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
74b2466e
LP
212 DnsResourceRecord *rr;
213
214 rr = new0(DnsResourceRecord, 1);
215 if (!rr)
216 return NULL;
217
218 rr->n_ref = 1;
faa133f3
LP
219 rr->key = dns_resource_key_ref(key);
220
74b2466e
LP
221 return rr;
222}
223
8bf52d3d
LP
224DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
225 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
226
227 key = dns_resource_key_new(class, type, name);
228 if (!key)
229 return NULL;
230
231 return dns_resource_record_new(key);
232}
233
74b2466e
LP
234DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
235 if (!rr)
236 return NULL;
237
238 assert(rr->n_ref > 0);
239 rr->n_ref++;
240
241 return rr;
242}
243
244DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
245 if (!rr)
246 return NULL;
247
248 assert(rr->n_ref > 0);
249
250 if (rr->n_ref > 1) {
251 rr->n_ref--;
252 return NULL;
253 }
254
faa133f3 255 if (rr->key) {
9de3e329 256 switch(rr->key->type) {
9c92ce6d
LP
257
258 case DNS_TYPE_SRV:
259 free(rr->srv.name);
260 break;
261
9de3e329
ZJS
262 case DNS_TYPE_PTR:
263 case DNS_TYPE_NS:
264 case DNS_TYPE_CNAME:
8ac4e9e1 265 case DNS_TYPE_DNAME:
faa133f3 266 free(rr->ptr.name);
9de3e329 267 break;
9c92ce6d 268
9de3e329 269 case DNS_TYPE_HINFO:
faa133f3
LP
270 free(rr->hinfo.cpu);
271 free(rr->hinfo.os);
9de3e329 272 break;
9c92ce6d 273
9de3e329 274 case DNS_TYPE_TXT:
9c92ce6d 275 case DNS_TYPE_SPF:
2001c805 276 dns_txt_item_free_all(rr->txt.items);
9de3e329 277 break;
9c92ce6d 278
9de3e329 279 case DNS_TYPE_SOA:
7e8e0422
LP
280 free(rr->soa.mname);
281 free(rr->soa.rname);
9de3e329 282 break;
9c92ce6d 283
9de3e329 284 case DNS_TYPE_MX:
946c7094 285 free(rr->mx.exchange);
9de3e329 286 break;
9c92ce6d 287
abf126a3
TG
288 case DNS_TYPE_DS:
289 free(rr->ds.digest);
290 break;
291
42cc2eeb 292 case DNS_TYPE_SSHFP:
549c1a25 293 free(rr->sshfp.fingerprint);
42cc2eeb
LP
294 break;
295
8db0d2f5
ZJS
296 case DNS_TYPE_DNSKEY:
297 free(rr->dnskey.key);
298 break;
299
151226ab
ZJS
300 case DNS_TYPE_RRSIG:
301 free(rr->rrsig.signer);
302 free(rr->rrsig.signature);
303 break;
304
50f1e641
TG
305 case DNS_TYPE_NSEC:
306 free(rr->nsec.next_domain_name);
307 bitmap_free(rr->nsec.types);
308 break;
309
5d45a880
TG
310 case DNS_TYPE_NSEC3:
311 free(rr->nsec3.next_hashed_name);
312 free(rr->nsec3.salt);
313 bitmap_free(rr->nsec3.types);
314 break;
315
0dae31d4 316 case DNS_TYPE_LOC:
9de3e329
ZJS
317 case DNS_TYPE_A:
318 case DNS_TYPE_AAAA:
319 break;
9c92ce6d 320
9de3e329 321 default:
faa133f3 322 free(rr->generic.data);
9de3e329 323 }
322345fd 324
faa133f3
LP
325 dns_resource_key_unref(rr->key);
326 }
322345fd 327
faa133f3 328 free(rr);
322345fd 329
322345fd
LP
330 return NULL;
331}
332
623a4c97
LP
333int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
334 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
335 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
336 _cleanup_free_ char *ptr = NULL;
337 int r;
338
339 assert(ret);
340 assert(address);
341 assert(hostname);
342
343 r = dns_name_reverse(family, address, &ptr);
344 if (r < 0)
345 return r;
346
347 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
348 if (!key)
349 return -ENOMEM;
350
351 ptr = NULL;
352
353 rr = dns_resource_record_new(key);
354 if (!rr)
355 return -ENOMEM;
356
357 rr->ptr.name = strdup(hostname);
358 if (!rr->ptr.name)
359 return -ENOMEM;
360
361 *ret = rr;
362 rr = NULL;
363
364 return 0;
365}
366
78c6a153
LP
367int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
368 DnsResourceRecord *rr;
369
370 assert(ret);
371 assert(address);
372 assert(family);
373
374 if (family == AF_INET) {
375
376 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
377 if (!rr)
378 return -ENOMEM;
379
380 rr->a.in_addr = address->in;
381
382 } else if (family == AF_INET6) {
383
384 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
385 if (!rr)
386 return -ENOMEM;
387
388 rr->aaaa.in6_addr = address->in6;
389 } else
390 return -EAFNOSUPPORT;
391
392 *ret = rr;
393
394 return 0;
395}
396
322345fd
LP
397int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
398 int r;
399
400 assert(a);
401 assert(b);
402
faa133f3 403 r = dns_resource_key_equal(a->key, b->key);
322345fd
LP
404 if (r <= 0)
405 return r;
406
fd0b4602
LP
407 if (a->unparseable != b->unparseable)
408 return 0;
409
410 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
2d4c5cbc 411
9c92ce6d
LP
412 case DNS_TYPE_SRV:
413 r = dns_name_equal(a->srv.name, b->srv.name);
414 if (r <= 0)
415 return r;
416
417 return a->srv.priority == b->srv.priority &&
418 a->srv.weight == b->srv.weight &&
419 a->srv.port == b->srv.port;
420
2d4c5cbc
LP
421 case DNS_TYPE_PTR:
422 case DNS_TYPE_NS:
423 case DNS_TYPE_CNAME:
8ac4e9e1 424 case DNS_TYPE_DNAME:
322345fd 425 return dns_name_equal(a->ptr.name, b->ptr.name);
2d4c5cbc
LP
426
427 case DNS_TYPE_HINFO:
428 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
429 strcaseeq(a->hinfo.os, b->hinfo.os);
430
9de3e329 431 case DNS_TYPE_SPF: /* exactly the same as TXT */
0f84a72e 432 case DNS_TYPE_TXT:
2001c805 433 return dns_txt_item_equal(a->txt.items, b->txt.items);
2e276efc 434
2d4c5cbc 435 case DNS_TYPE_A:
322345fd 436 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
2d4c5cbc
LP
437
438 case DNS_TYPE_AAAA:
322345fd 439 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
2d4c5cbc
LP
440
441 case DNS_TYPE_SOA:
7e8e0422
LP
442 r = dns_name_equal(a->soa.mname, b->soa.mname);
443 if (r <= 0)
444 return r;
445 r = dns_name_equal(a->soa.rname, b->soa.rname);
446 if (r <= 0)
447 return r;
448
449 return a->soa.serial == b->soa.serial &&
450 a->soa.refresh == b->soa.refresh &&
451 a->soa.retry == b->soa.retry &&
452 a->soa.expire == b->soa.expire &&
453 a->soa.minimum == b->soa.minimum;
9c92ce6d 454
946c7094
ZJS
455 case DNS_TYPE_MX:
456 if (a->mx.priority != b->mx.priority)
457 return 0;
458
459 return dns_name_equal(a->mx.exchange, b->mx.exchange);
460
0dae31d4
ZJS
461 case DNS_TYPE_LOC:
462 assert(a->loc.version == b->loc.version);
463
464 return a->loc.size == b->loc.size &&
465 a->loc.horiz_pre == b->loc.horiz_pre &&
466 a->loc.vert_pre == b->loc.vert_pre &&
467 a->loc.latitude == b->loc.latitude &&
468 a->loc.longitude == b->loc.longitude &&
469 a->loc.altitude == b->loc.altitude;
470
abf126a3
TG
471 case DNS_TYPE_DS:
472 return a->ds.key_tag == b->ds.key_tag &&
473 a->ds.algorithm == b->ds.algorithm &&
474 a->ds.digest_type == b->ds.digest_type &&
475 a->ds.digest_size == b->ds.digest_size &&
476 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
477
42cc2eeb
LP
478 case DNS_TYPE_SSHFP:
479 return a->sshfp.algorithm == b->sshfp.algorithm &&
480 a->sshfp.fptype == b->sshfp.fptype &&
549c1a25
TG
481 a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
482 memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
42cc2eeb 483
8db0d2f5
ZJS
484 case DNS_TYPE_DNSKEY:
485 return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag &&
486 a->dnskey.sep_flag == b->dnskey.sep_flag &&
487 a->dnskey.algorithm == b->dnskey.algorithm &&
488 a->dnskey.key_size == b->dnskey.key_size &&
489 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
490
151226ab
ZJS
491 case DNS_TYPE_RRSIG:
492 /* do the fast comparisons first */
03664a62
LN
493 if (a->rrsig.type_covered != b->rrsig.type_covered ||
494 a->rrsig.algorithm != b->rrsig.algorithm ||
495 a->rrsig.labels != b->rrsig.labels ||
496 a->rrsig.original_ttl != b->rrsig.original_ttl ||
497 a->rrsig.expiration != b->rrsig.expiration ||
498 a->rrsig.inception != b->rrsig.inception ||
499 a->rrsig.key_tag != b->rrsig.key_tag ||
151226ab
ZJS
500 a->rrsig.signature_size != b->rrsig.signature_size ||
501 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
502 return false;
503
504 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
505
50f1e641
TG
506 case DNS_TYPE_NSEC:
507 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
508 bitmap_equal(a->nsec.types, b->nsec.types);
509
5d45a880
TG
510 case DNS_TYPE_NSEC3:
511 return a->nsec3.algorithm == b->nsec3.algorithm &&
512 a->nsec3.flags == b->nsec3.flags &&
513 a->nsec3.iterations == b->nsec3.iterations &&
514 a->nsec3.salt_size == b->nsec3.salt_size &&
515 memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
516 memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
517 bitmap_equal(a->nsec3.types, b->nsec3.types);
518
2d4c5cbc 519 default:
322345fd
LP
520 return a->generic.size == b->generic.size &&
521 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
2d4c5cbc 522 }
322345fd
LP
523}
524
0dae31d4
ZJS
525static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
526 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
527 char *s;
528 char NS = latitude >= 1U<<31 ? 'N' : 'S';
529 char EW = longitude >= 1U<<31 ? 'E' : 'W';
530
531 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
532 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
533 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
534 double siz = (size >> 4) * exp10((double) (size & 0xF));
535 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
536 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
537
538 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
539 (lat / 60000 / 60),
540 (lat / 60000) % 60,
541 (lat % 60000) / 1000.,
542 NS,
543 (lon / 60000 / 60),
544 (lon / 60000) % 60,
545 (lon % 60000) / 1000.,
546 EW,
547 alt / 100.,
548 siz / 100.,
549 hor / 100.,
550 ver / 100.) < 0)
551 return NULL;
552
553 return s;
554}
555
7c6423e1
TG
556static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
557 struct tm tm;
558
559 assert(buf);
560 assert(l > strlen("YYYYMMDDHHmmSS"));
561
562 if (!gmtime_r(&sec, &tm))
563 return -EINVAL;
564
565 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
566 return -EINVAL;
567
568 return 0;
569}
570
50f1e641
TG
571static char *format_types(Bitmap *types) {
572 _cleanup_strv_free_ char **strv = NULL;
573 _cleanup_free_ char *str = NULL;
cb57dd41 574 Iterator i;
50f1e641
TG
575 unsigned type;
576 int r;
577
cb57dd41 578 BITMAP_FOREACH(type, types, i) {
50f1e641 579 if (dns_type_to_string(type)) {
2c1fb4f7 580 r = strv_extend(&strv, dns_type_to_string(type));
50f1e641
TG
581 if (r < 0)
582 return NULL;
583 } else {
584 char *t;
585
586 r = asprintf(&t, "TYPE%u", type);
587 if (r < 0)
588 return NULL;
589
2c1fb4f7 590 r = strv_consume(&strv, t);
50f1e641
TG
591 if (r < 0)
592 return NULL;
593 }
594 }
595
596 str = strv_join(strv, " ");
597 if (!str)
598 return NULL;
599
600 return strjoin("( ", str, " )", NULL);
601}
602
2001c805
LP
603static char *format_txt(DnsTxtItem *first) {
604 DnsTxtItem *i;
605 size_t c = 1;
606 char *p, *s;
607
608 LIST_FOREACH(items, i, first)
609 c += i->length * 4 + 3;
610
611 p = s = new(char, c);
612 if (!s)
613 return NULL;
614
615 LIST_FOREACH(items, i, first) {
616 size_t j;
617
618 if (i != first)
619 *(p++) = ' ';
620
621 *(p++) = '"';
622
623 for (j = 0; j < i->length; j++) {
624 if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) {
625 *(p++) = '\\';
626 *(p++) = '0' + (i->data[j] / 100);
627 *(p++) = '0' + ((i->data[j] / 10) % 10);
628 *(p++) = '0' + (i->data[j] % 10);
629 } else
630 *(p++) = i->data[j];
631 }
632
633 *(p++) = '"';
634 }
635
636 *p = 0;
637 return s;
638}
639
2d4c5cbc 640int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
8db0d2f5 641 _cleanup_free_ char *k = NULL, *t = NULL;
2d4c5cbc
LP
642 char *s;
643 int r;
322345fd 644
2d4c5cbc 645 assert(rr);
322345fd 646
2d4c5cbc
LP
647 r = dns_resource_key_to_string(rr->key, &k);
648 if (r < 0)
649 return r;
322345fd 650
0dae31d4 651 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
322345fd 652
9c92ce6d
LP
653 case DNS_TYPE_SRV:
654 r = asprintf(&s, "%s %u %u %u %s",
655 k,
656 rr->srv.priority,
657 rr->srv.weight,
658 rr->srv.port,
659 strna(rr->srv.name));
660 if (r < 0)
661 return -ENOMEM;
662 break;
663
2d4c5cbc
LP
664 case DNS_TYPE_PTR:
665 case DNS_TYPE_NS:
666 case DNS_TYPE_CNAME:
8ac4e9e1 667 case DNS_TYPE_DNAME:
2d4c5cbc
LP
668 s = strjoin(k, " ", rr->ptr.name, NULL);
669 if (!s)
670 return -ENOMEM;
322345fd 671
2d4c5cbc 672 break;
322345fd 673
2d4c5cbc
LP
674 case DNS_TYPE_HINFO:
675 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
676 if (!s)
677 return -ENOMEM;
678 break;
322345fd 679
9de3e329 680 case DNS_TYPE_SPF: /* exactly the same as TXT */
8db0d2f5 681 case DNS_TYPE_TXT:
2001c805 682 t = format_txt(rr->txt.items);
2e276efc
ZJS
683 if (!t)
684 return -ENOMEM;
685
686 s = strjoin(k, " ", t, NULL);
687 if (!s)
688 return -ENOMEM;
2e276efc 689 break;
2e276efc 690
2d4c5cbc
LP
691 case DNS_TYPE_A: {
692 _cleanup_free_ char *x = NULL;
322345fd 693
2d4c5cbc
LP
694 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
695 if (r < 0)
696 return r;
322345fd 697
2d4c5cbc
LP
698 s = strjoin(k, " ", x, NULL);
699 if (!s)
700 return -ENOMEM;
701 break;
702 }
322345fd 703
8db0d2f5
ZJS
704 case DNS_TYPE_AAAA:
705 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
2d4c5cbc
LP
706 if (r < 0)
707 return r;
322345fd 708
8db0d2f5 709 s = strjoin(k, " ", t, NULL);
2d4c5cbc
LP
710 if (!s)
711 return -ENOMEM;
712 break;
322345fd 713
2d4c5cbc
LP
714 case DNS_TYPE_SOA:
715 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
716 k,
717 strna(rr->soa.mname),
718 strna(rr->soa.rname),
719 rr->soa.serial,
720 rr->soa.refresh,
721 rr->soa.retry,
722 rr->soa.expire,
723 rr->soa.minimum);
724 if (r < 0)
725 return -ENOMEM;
726 break;
727
946c7094
ZJS
728 case DNS_TYPE_MX:
729 r = asprintf(&s, "%s %u %s",
730 k,
731 rr->mx.priority,
732 rr->mx.exchange);
733 if (r < 0)
734 return -ENOMEM;
735 break;
736
8db0d2f5 737 case DNS_TYPE_LOC:
0dae31d4
ZJS
738 assert(rr->loc.version == 0);
739
8db0d2f5
ZJS
740 t = format_location(rr->loc.latitude,
741 rr->loc.longitude,
742 rr->loc.altitude,
743 rr->loc.size,
744 rr->loc.horiz_pre,
745 rr->loc.vert_pre);
746 if (!t)
0dae31d4
ZJS
747 return -ENOMEM;
748
8db0d2f5 749 s = strjoin(k, " ", t, NULL);
0dae31d4
ZJS
750 if (!s)
751 return -ENOMEM;
0dae31d4 752 break;
0dae31d4 753
abf126a3
TG
754 case DNS_TYPE_DS:
755 t = hexmem(rr->ds.digest, rr->ds.digest_size);
756 if (!t)
757 return -ENOMEM;
758
759 r = asprintf(&s, "%s %u %u %u %s",
760 k,
761 rr->ds.key_tag,
762 rr->ds.algorithm,
763 rr->ds.digest_type,
764 t);
765 if (r < 0)
766 return -ENOMEM;
767 break;
768
8db0d2f5 769 case DNS_TYPE_SSHFP:
549c1a25 770 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
8db0d2f5 771 if (!t)
42cc2eeb
LP
772 return -ENOMEM;
773
774 r = asprintf(&s, "%s %u %u %s",
775 k,
776 rr->sshfp.algorithm,
777 rr->sshfp.fptype,
8db0d2f5 778 t);
42cc2eeb
LP
779 if (r < 0)
780 return -ENOMEM;
781 break;
42cc2eeb 782
ff3d6560
ZJS
783 case DNS_TYPE_DNSKEY: {
784 const char *alg;
785
786 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
787
1bf968f3 788 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
8db0d2f5
ZJS
789 if (!t)
790 return -ENOMEM;
2d4c5cbc 791
ff3d6560 792 r = asprintf(&s, "%s %u 3 %.*s%.*u %s",
8db0d2f5
ZJS
793 k,
794 dnskey_to_flags(rr),
ff3d6560
ZJS
795 alg ? -1 : 0, alg,
796 alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
8db0d2f5
ZJS
797 t);
798 if (r < 0)
2d4c5cbc 799 return -ENOMEM;
8db0d2f5 800 break;
ff3d6560 801 }
2d4c5cbc 802
151226ab
ZJS
803 case DNS_TYPE_RRSIG: {
804 const char *type, *alg;
7c6423e1 805 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
151226ab
ZJS
806
807 type = dns_type_to_string(rr->rrsig.type_covered);
808 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
809
1bf968f3 810 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
151226ab
ZJS
811 if (!t)
812 return -ENOMEM;
813
7c6423e1
TG
814 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
815 if (r < 0)
816 return r;
817
818 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
819 if (r < 0)
820 return r;
821
151226ab
ZJS
822 /* TYPE?? follows
823 * http://tools.ietf.org/html/rfc3597#section-5 */
824
7c6423e1 825 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
151226ab
ZJS
826 k,
827 type ?: "TYPE",
828 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
829 alg ? -1 : 0, alg,
830 alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
831 rr->rrsig.labels,
832 rr->rrsig.original_ttl,
7c6423e1
TG
833 expiration,
834 inception,
151226ab
ZJS
835 rr->rrsig.key_tag,
836 rr->rrsig.signer,
837 t);
838 if (r < 0)
839 return -ENOMEM;
840 break;
841 }
842
50f1e641
TG
843 case DNS_TYPE_NSEC:
844 t = format_types(rr->nsec.types);
845 if (!t)
846 return -ENOMEM;
847
848 r = asprintf(&s, "%s %s %s",
849 k,
850 rr->nsec.next_domain_name,
851 t);
852 if (r < 0)
853 return -ENOMEM;
854 break;
855
5d45a880
TG
856 case DNS_TYPE_NSEC3: {
857 _cleanup_free_ char *salt = NULL, *hash = NULL;
858
f5430a3e 859 if (rr->nsec3.salt_size > 0) {
5d45a880
TG
860 salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
861 if (!salt)
862 return -ENOMEM;
863 }
864
865 hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
866 if (!hash)
867 return -ENOMEM;
868
869 t = format_types(rr->nsec3.types);
870 if (!t)
871 return -ENOMEM;
872
873 r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
874 k,
875 rr->nsec3.algorithm,
876 rr->nsec3.flags,
877 rr->nsec3.iterations,
f5430a3e 878 rr->nsec3.salt_size > 0 ? salt : "-",
5d45a880
TG
879 hash,
880 t);
881 if (r < 0)
882 return -ENOMEM;
883
884 break;
885 }
886
8db0d2f5
ZJS
887 default:
888 t = hexmem(rr->generic.data, rr->generic.size);
889 if (!t)
890 return -ENOMEM;
891
f5430a3e 892 r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
d23a27a9 893 if (r < 0)
2d4c5cbc
LP
894 return -ENOMEM;
895 break;
8db0d2f5 896 }
2d4c5cbc
LP
897
898 *ret = s;
899 return 0;
900}
322345fd 901
2d4c5cbc 902const char *dns_class_to_string(uint16_t class) {
322345fd 903
2d4c5cbc 904 switch (class) {
322345fd 905
2d4c5cbc
LP
906 case DNS_CLASS_IN:
907 return "IN";
322345fd 908
2d4c5cbc
LP
909 case DNS_CLASS_ANY:
910 return "ANY";
911 }
322345fd 912
2d4c5cbc
LP
913 return NULL;
914}
322345fd 915
2d4c5cbc
LP
916int dns_class_from_string(const char *s, uint16_t *class) {
917 assert(s);
918 assert(class);
919
920 if (strcaseeq(s, "IN"))
921 *class = DNS_CLASS_IN;
922 else if (strcaseeq(s, "ANY"))
816b4547 923 *class = DNS_CLASS_ANY;
2d4c5cbc
LP
924 else
925 return -EINVAL;
322345fd 926
2d4c5cbc
LP
927 return 0;
928}
2001c805
LP
929
930DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
931 DnsTxtItem *n;
932
933 if (!i)
934 return NULL;
935
936 n = i->items_next;
937
938 free(i);
939 return dns_txt_item_free_all(n);
940}
941
942bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
943
944 if (!a != !b)
945 return false;
946
947 if (!a)
948 return true;
949
950 if (a->length != b->length)
951 return false;
952
953 if (memcmp(a->data, b->data, a->length) != 0)
954 return false;
955
956 return dns_txt_item_equal(a->items_next, b->items_next);
957}