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