]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-rr.c
resolved: TXT records
[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
2e276efc
ZJS
22#include "strv.h"
23
322345fd 24#include "resolved-dns-domain.h"
74b2466e
LP
25#include "resolved-dns-rr.h"
26
faa133f3
LP
27DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
28 DnsResourceKey *k;
29 size_t l;
74b2466e 30
faa133f3
LP
31 assert(name);
32
33 l = strlen(name);
34 k = malloc0(sizeof(DnsResourceKey) + l + 1);
35 if (!k)
36 return NULL;
37
38 k->n_ref = 1;
39 k->class = class;
40 k->type = type;
41
42 strcpy((char*) k + sizeof(DnsResourceKey), name);
43
44 return k;
45}
46
47DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
48 DnsResourceKey *k;
49
50 assert(name);
51
52 k = new0(DnsResourceKey, 1);
53 if (!k)
54 return NULL;
55
56 k->n_ref = 1;
57 k->class = class;
58 k->type = type;
59 k->_name = name;
60
61 return k;
62}
63
64DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
65
66 if (!k)
67 return NULL;
68
69 assert(k->n_ref > 0);
70 k->n_ref++;
71
72 return k;
73}
74
75DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
76 if (!k)
77 return NULL;
78
79 assert(k->n_ref > 0);
80
81 if (k->n_ref == 1) {
82 free(k->_name);
83 free(k);
84 } else
85 k->n_ref--;
86
87 return NULL;
88}
89
90int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
91 int r;
92
93 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
94 if (r <= 0)
95 return r;
96
97 if (a->class != b->class)
98 return 0;
99
100 if (a->type != b->type)
101 return 0;
102
103 return 1;
104}
105
106int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr) {
107 assert(key);
108 assert(rr);
109
110 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
111 return 0;
112
113 if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
114 return 0;
115
116 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
117}
118
119int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr) {
120 assert(key);
121 assert(rr);
122
123 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
124 return 0;
125
126 if (rr->key->type != DNS_TYPE_CNAME)
127 return 0;
128
129 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
74b2466e
LP
130}
131
322345fd
LP
132unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]) {
133 const DnsResourceKey *k = i;
134 unsigned long ul;
135
faa133f3 136 ul = dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), hash_key);
322345fd
LP
137 ul = ul * hash_key[0] + ul + k->class;
138 ul = ul * hash_key[1] + ul + k->type;
139
140 return ul;
141}
142
143int dns_resource_key_compare_func(const void *a, const void *b) {
144 const DnsResourceKey *x = a, *y = b;
145 int ret;
146
faa133f3 147 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
322345fd
LP
148 if (ret != 0)
149 return ret;
150
151 if (x->type < y->type)
152 return -1;
153 if (x->type > y->type)
154 return 1;
155
156 if (x->class < y->class)
157 return -1;
158 if (x->class > y->class)
159 return 1;
160
161 return 0;
162}
163
2d4c5cbc
LP
164int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
165 char cbuf[DECIMAL_STR_MAX(uint16_t)], tbuf[DECIMAL_STR_MAX(uint16_t)];
166 const char *c, *t;
167 char *s;
168
169 c = dns_class_to_string(key->class);
170 if (!c) {
171 sprintf(cbuf, "%i", key->class);
172 c = cbuf;
173 }
174
175 t = dns_type_to_string(key->type);
176 if (!t){
177 sprintf(tbuf, "%i", key->type);
178 t = tbuf;
179 }
180
181 s = strjoin(DNS_RESOURCE_KEY_NAME(key), " ", c, " ", t, NULL);
182 if (!s)
183 return -ENOMEM;
184
185 *ret = s;
186 return 0;
187}
188
faa133f3 189DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
74b2466e
LP
190 DnsResourceRecord *rr;
191
192 rr = new0(DnsResourceRecord, 1);
193 if (!rr)
194 return NULL;
195
196 rr->n_ref = 1;
faa133f3
LP
197 rr->key = dns_resource_key_ref(key);
198
74b2466e
LP
199 return rr;
200}
201
8bf52d3d
LP
202DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
203 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
204
205 key = dns_resource_key_new(class, type, name);
206 if (!key)
207 return NULL;
208
209 return dns_resource_record_new(key);
210}
211
74b2466e
LP
212DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
213 if (!rr)
214 return NULL;
215
216 assert(rr->n_ref > 0);
217 rr->n_ref++;
218
219 return rr;
220}
221
222DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
223 if (!rr)
224 return NULL;
225
226 assert(rr->n_ref > 0);
227
228 if (rr->n_ref > 1) {
229 rr->n_ref--;
230 return NULL;
231 }
232
faa133f3
LP
233 if (rr->key) {
234 if (IN_SET(rr->key->type, DNS_TYPE_PTR, DNS_TYPE_NS, DNS_TYPE_CNAME))
235 free(rr->ptr.name);
236 else if (rr->key->type == DNS_TYPE_HINFO) {
237 free(rr->hinfo.cpu);
238 free(rr->hinfo.os);
2e276efc
ZJS
239 } else if (rr->key->type == DNS_TYPE_TXT) {
240 strv_free(rr->txt.strings);
7e8e0422
LP
241 } else if (rr->key->type == DNS_TYPE_SOA) {
242 free(rr->soa.mname);
243 free(rr->soa.rname);
946c7094
ZJS
244 } else if (rr->key->type == DNS_TYPE_MX) {
245 free(rr->mx.exchange);
faa133f3
LP
246 } else if (!IN_SET(rr->key->type, DNS_TYPE_A, DNS_TYPE_AAAA))
247 free(rr->generic.data);
322345fd 248
faa133f3
LP
249 dns_resource_key_unref(rr->key);
250 }
322345fd 251
faa133f3 252 free(rr);
322345fd 253
322345fd
LP
254 return NULL;
255}
256
623a4c97
LP
257int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
258 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
259 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
260 _cleanup_free_ char *ptr = NULL;
261 int r;
262
263 assert(ret);
264 assert(address);
265 assert(hostname);
266
267 r = dns_name_reverse(family, address, &ptr);
268 if (r < 0)
269 return r;
270
271 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
272 if (!key)
273 return -ENOMEM;
274
275 ptr = NULL;
276
277 rr = dns_resource_record_new(key);
278 if (!rr)
279 return -ENOMEM;
280
281 rr->ptr.name = strdup(hostname);
282 if (!rr->ptr.name)
283 return -ENOMEM;
284
285 *ret = rr;
286 rr = NULL;
287
288 return 0;
289}
290
322345fd
LP
291int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
292 int r;
293
294 assert(a);
295 assert(b);
296
faa133f3 297 r = dns_resource_key_equal(a->key, b->key);
322345fd
LP
298 if (r <= 0)
299 return r;
300
2d4c5cbc
LP
301 switch (a->key->type) {
302
303 case DNS_TYPE_PTR:
304 case DNS_TYPE_NS:
305 case DNS_TYPE_CNAME:
322345fd 306 return dns_name_equal(a->ptr.name, b->ptr.name);
2d4c5cbc
LP
307
308 case DNS_TYPE_HINFO:
309 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
310 strcaseeq(a->hinfo.os, b->hinfo.os);
311
2e276efc
ZJS
312 case DNS_TYPE_TXT: {
313 int i;
314
315 for (i = 0; a->txt.strings[i] || b->txt.strings[i]; i++)
316 if (!streq_ptr(a->txt.strings[i], b->txt.strings[i]))
317 return false;
318 return true;
319 }
320
2d4c5cbc 321 case DNS_TYPE_A:
322345fd 322 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
2d4c5cbc
LP
323
324 case DNS_TYPE_AAAA:
322345fd 325 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
2d4c5cbc
LP
326
327 case DNS_TYPE_SOA:
7e8e0422
LP
328 r = dns_name_equal(a->soa.mname, b->soa.mname);
329 if (r <= 0)
330 return r;
331 r = dns_name_equal(a->soa.rname, b->soa.rname);
332 if (r <= 0)
333 return r;
334
335 return a->soa.serial == b->soa.serial &&
336 a->soa.refresh == b->soa.refresh &&
337 a->soa.retry == b->soa.retry &&
338 a->soa.expire == b->soa.expire &&
339 a->soa.minimum == b->soa.minimum;
946c7094
ZJS
340 case DNS_TYPE_MX:
341 if (a->mx.priority != b->mx.priority)
342 return 0;
343
344 return dns_name_equal(a->mx.exchange, b->mx.exchange);
345
2d4c5cbc 346 default:
322345fd
LP
347 return a->generic.size == b->generic.size &&
348 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
2d4c5cbc 349 }
322345fd
LP
350}
351
2d4c5cbc
LP
352int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
353 _cleanup_free_ char *k = NULL;
354 char *s;
355 int r;
322345fd 356
2d4c5cbc 357 assert(rr);
322345fd 358
2d4c5cbc
LP
359 r = dns_resource_key_to_string(rr->key, &k);
360 if (r < 0)
361 return r;
322345fd 362
2d4c5cbc 363 switch (rr->key->type) {
322345fd 364
2d4c5cbc
LP
365 case DNS_TYPE_PTR:
366 case DNS_TYPE_NS:
367 case DNS_TYPE_CNAME:
368 s = strjoin(k, " ", rr->ptr.name, NULL);
369 if (!s)
370 return -ENOMEM;
322345fd 371
2d4c5cbc 372 break;
322345fd 373
2d4c5cbc
LP
374 case DNS_TYPE_HINFO:
375 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
376 if (!s)
377 return -ENOMEM;
378 break;
322345fd 379
2e276efc
ZJS
380 case DNS_TYPE_TXT: {
381 _cleanup_free_ char *t;
382
383 t = strv_join_quoted(rr->txt.strings);
384 if (!t)
385 return -ENOMEM;
386
387 s = strjoin(k, " ", t, NULL);
388 if (!s)
389 return -ENOMEM;
390
391 break;
392 }
393
2d4c5cbc
LP
394 case DNS_TYPE_A: {
395 _cleanup_free_ char *x = NULL;
322345fd 396
2d4c5cbc
LP
397 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
398 if (r < 0)
399 return r;
322345fd 400
2d4c5cbc
LP
401 s = strjoin(k, " ", x, NULL);
402 if (!s)
403 return -ENOMEM;
404 break;
405 }
322345fd 406
2d4c5cbc
LP
407 case DNS_TYPE_AAAA: {
408 _cleanup_free_ char *x = NULL;
322345fd 409
2d4c5cbc
LP
410 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &x);
411 if (r < 0)
412 return r;
322345fd 413
2d4c5cbc
LP
414 s = strjoin(k, " ", x, NULL);
415 if (!s)
416 return -ENOMEM;
417 break;
418 }
322345fd 419
2d4c5cbc
LP
420 case DNS_TYPE_SOA:
421 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
422 k,
423 strna(rr->soa.mname),
424 strna(rr->soa.rname),
425 rr->soa.serial,
426 rr->soa.refresh,
427 rr->soa.retry,
428 rr->soa.expire,
429 rr->soa.minimum);
430 if (r < 0)
431 return -ENOMEM;
432 break;
433
946c7094
ZJS
434 case DNS_TYPE_MX:
435 r = asprintf(&s, "%s %u %s",
436 k,
437 rr->mx.priority,
438 rr->mx.exchange);
439 if (r < 0)
440 return -ENOMEM;
441 break;
442
2d4c5cbc
LP
443 default: {
444 _cleanup_free_ char *x = NULL;
445
446 x = hexmem(rr->generic.data, rr->generic.size);
447 if (!x)
448 return -ENOMEM;
449
450 s = strjoin(k, " ", x, NULL);
451 if (!s)
452 return -ENOMEM;
453 break;
454 }}
455
456 *ret = s;
457 return 0;
458}
322345fd 459
2d4c5cbc 460const char *dns_class_to_string(uint16_t class) {
322345fd 461
2d4c5cbc 462 switch (class) {
322345fd 463
2d4c5cbc
LP
464 case DNS_CLASS_IN:
465 return "IN";
322345fd 466
2d4c5cbc
LP
467 case DNS_CLASS_ANY:
468 return "ANY";
469 }
322345fd 470
2d4c5cbc
LP
471 return NULL;
472}
322345fd 473
2d4c5cbc
LP
474int dns_class_from_string(const char *s, uint16_t *class) {
475 assert(s);
476 assert(class);
477
478 if (strcaseeq(s, "IN"))
479 *class = DNS_CLASS_IN;
480 else if (strcaseeq(s, "ANY"))
481 *class = DNS_TYPE_ANY;
482 else
483 return -EINVAL;
322345fd 484
2d4c5cbc
LP
485 return 0;
486}
322345fd 487
2d4c5cbc
LP
488static const struct {
489 uint16_t type;
490 const char *name;
491} dns_types[] = {
492 { DNS_TYPE_A, "A" },
493 { DNS_TYPE_NS, "NS" },
494 { DNS_TYPE_CNAME, "CNAME" },
495 { DNS_TYPE_SOA, "SOA" },
496 { DNS_TYPE_PTR, "PTR" },
497 { DNS_TYPE_HINFO, "HINFO" },
498 { DNS_TYPE_MX, "MX" },
499 { DNS_TYPE_TXT, "TXT" },
500 { DNS_TYPE_AAAA, "AAAA" },
501 { DNS_TYPE_SRV, "SRV" },
502 { DNS_TYPE_SSHFP, "SSHFP" },
503 { DNS_TYPE_DNAME, "DNAME" },
504 { DNS_TYPE_ANY, "ANY" },
505 { DNS_TYPE_OPT, "OPT" },
506 { DNS_TYPE_TKEY, "TKEY" },
507 { DNS_TYPE_TSIG, "TSIG" },
508 { DNS_TYPE_IXFR, "IXFR" },
509 { DNS_TYPE_AXFR, "AXFR" },
510};
322345fd 511
322345fd 512
2d4c5cbc
LP
513const char *dns_type_to_string(uint16_t type) {
514 unsigned i;
322345fd 515
2d4c5cbc
LP
516 for (i = 0; i < ELEMENTSOF(dns_types); i++)
517 if (dns_types[i].type == type)
518 return dns_types[i].name;
322345fd
LP
519
520 return NULL;
521}
2d4c5cbc
LP
522
523int dns_type_from_string(const char *s, uint16_t *type) {
524 unsigned i;
525
526 assert(s);
527 assert(type);
528
529 for (i = 0; i < ELEMENTSOF(dns_types); i++)
530 if (strcaseeq(dns_types[i].name, s)) {
531 *type = dns_types[i].type;
532 return 0;
533 }
534
535 return -EINVAL;
536}