resolve-host: list types and classes
[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
322345fd 22#include "resolved-dns-domain.h"
74b2466e
LP
23#include "resolved-dns-rr.h"
24
faa133f3
LP
25DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
26 DnsResourceKey *k;
27 size_t l;
74b2466e 28
faa133f3
LP
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
45DnsResourceKey* 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
62DnsResourceKey* 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
73DnsResourceKey* 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
88int 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
104int 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
117int 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));
74b2466e
LP
128}
129
322345fd
LP
130unsigned 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
faa133f3 134 ul = dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), hash_key);
322345fd
LP
135 ul = ul * hash_key[0] + ul + k->class;
136 ul = ul * hash_key[1] + ul + k->type;
137
138 return ul;
139}
140
141int dns_resource_key_compare_func(const void *a, const void *b) {
142 const DnsResourceKey *x = a, *y = b;
143 int ret;
144
faa133f3 145 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
322345fd
LP
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
2d4c5cbc
LP
162int 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
faa133f3 187DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
74b2466e
LP
188 DnsResourceRecord *rr;
189
190 rr = new0(DnsResourceRecord, 1);
191 if (!rr)
192 return NULL;
193
194 rr->n_ref = 1;
faa133f3
LP
195 rr->key = dns_resource_key_ref(key);
196
74b2466e
LP
197 return rr;
198}
199
8bf52d3d
LP
200DnsResourceRecord* 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
74b2466e
LP
210DnsResourceRecord* 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
220DnsResourceRecord* 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
faa133f3
LP
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);
7e8e0422
LP
237 } else if (rr->key->type == DNS_TYPE_SOA) {
238 free(rr->soa.mname);
239 free(rr->soa.rname);
faa133f3
LP
240 } else if (!IN_SET(rr->key->type, DNS_TYPE_A, DNS_TYPE_AAAA))
241 free(rr->generic.data);
322345fd 242
faa133f3
LP
243 dns_resource_key_unref(rr->key);
244 }
322345fd 245
faa133f3 246 free(rr);
322345fd 247
322345fd
LP
248 return NULL;
249}
250
623a4c97
LP
251int 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
322345fd
LP
285int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
286 int r;
287
288 assert(a);
289 assert(b);
290
faa133f3 291 r = dns_resource_key_equal(a->key, b->key);
322345fd
LP
292 if (r <= 0)
293 return r;
294
2d4c5cbc
LP
295 switch (a->key->type) {
296
297 case DNS_TYPE_PTR:
298 case DNS_TYPE_NS:
299 case DNS_TYPE_CNAME:
322345fd 300 return dns_name_equal(a->ptr.name, b->ptr.name);
2d4c5cbc
LP
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:
322345fd 307 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
2d4c5cbc
LP
308
309 case DNS_TYPE_AAAA:
322345fd 310 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
2d4c5cbc
LP
311
312 case DNS_TYPE_SOA:
7e8e0422
LP
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;
2d4c5cbc 325 default:
322345fd
LP
326 return a->generic.size == b->generic.size &&
327 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
2d4c5cbc 328 }
322345fd
LP
329}
330
2d4c5cbc
LP
331int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
332 _cleanup_free_ char *k = NULL;
333 char *s;
334 int r;
322345fd 335
2d4c5cbc 336 assert(rr);
322345fd 337
2d4c5cbc
LP
338 r = dns_resource_key_to_string(rr->key, &k);
339 if (r < 0)
340 return r;
322345fd 341
2d4c5cbc 342 switch (rr->key->type) {
322345fd 343
2d4c5cbc
LP
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;
322345fd 350
2d4c5cbc 351 break;
322345fd 352
2d4c5cbc
LP
353 case DNS_TYPE_HINFO:
354 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
355 if (!s)
356 return -ENOMEM;
357 break;
322345fd 358
2d4c5cbc
LP
359 case DNS_TYPE_A: {
360 _cleanup_free_ char *x = NULL;
322345fd 361
2d4c5cbc
LP
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;
322345fd 365
2d4c5cbc
LP
366 s = strjoin(k, " ", x, NULL);
367 if (!s)
368 return -ENOMEM;
369 break;
370 }
322345fd 371
2d4c5cbc
LP
372 case DNS_TYPE_AAAA: {
373 _cleanup_free_ char *x = NULL;
322345fd 374
2d4c5cbc
LP
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;
322345fd 378
2d4c5cbc
LP
379 s = strjoin(k, " ", x, NULL);
380 if (!s)
381 return -ENOMEM;
382 break;
383 }
322345fd 384
2d4c5cbc
LP
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}
322345fd 415
2d4c5cbc 416const char *dns_class_to_string(uint16_t class) {
322345fd 417
2d4c5cbc 418 switch (class) {
322345fd 419
2d4c5cbc
LP
420 case DNS_CLASS_IN:
421 return "IN";
322345fd 422
2d4c5cbc
LP
423 case DNS_CLASS_ANY:
424 return "ANY";
425 }
322345fd 426
2d4c5cbc
LP
427 return NULL;
428}
322345fd 429
2d4c5cbc
LP
430int 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;
322345fd 440
2d4c5cbc
LP
441 return 0;
442}
322345fd 443
2d4c5cbc
LP
444static 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};
322345fd 467
322345fd 468
2d4c5cbc
LP
469const char *dns_type_to_string(uint16_t type) {
470 unsigned i;
322345fd 471
2d4c5cbc
LP
472 for (i = 0; i < ELEMENTSOF(dns_types); i++)
473 if (dns_types[i].type == type)
474 return dns_types[i].name;
322345fd
LP
475
476 return NULL;
477}
2d4c5cbc
LP
478
479int 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}