]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-rr.c
resolved: MX 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
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);
946c7094
ZJS
240 } else if (rr->key->type == DNS_TYPE_MX) {
241 free(rr->mx.exchange);
faa133f3
LP
242 } else if (!IN_SET(rr->key->type, DNS_TYPE_A, DNS_TYPE_AAAA))
243 free(rr->generic.data);
322345fd 244
faa133f3
LP
245 dns_resource_key_unref(rr->key);
246 }
322345fd 247
faa133f3 248 free(rr);
322345fd 249
322345fd
LP
250 return NULL;
251}
252
623a4c97
LP
253int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
254 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
255 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
256 _cleanup_free_ char *ptr = NULL;
257 int r;
258
259 assert(ret);
260 assert(address);
261 assert(hostname);
262
263 r = dns_name_reverse(family, address, &ptr);
264 if (r < 0)
265 return r;
266
267 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
268 if (!key)
269 return -ENOMEM;
270
271 ptr = NULL;
272
273 rr = dns_resource_record_new(key);
274 if (!rr)
275 return -ENOMEM;
276
277 rr->ptr.name = strdup(hostname);
278 if (!rr->ptr.name)
279 return -ENOMEM;
280
281 *ret = rr;
282 rr = NULL;
283
284 return 0;
285}
286
322345fd
LP
287int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
288 int r;
289
290 assert(a);
291 assert(b);
292
faa133f3 293 r = dns_resource_key_equal(a->key, b->key);
322345fd
LP
294 if (r <= 0)
295 return r;
296
2d4c5cbc
LP
297 switch (a->key->type) {
298
299 case DNS_TYPE_PTR:
300 case DNS_TYPE_NS:
301 case DNS_TYPE_CNAME:
322345fd 302 return dns_name_equal(a->ptr.name, b->ptr.name);
2d4c5cbc
LP
303
304 case DNS_TYPE_HINFO:
305 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
306 strcaseeq(a->hinfo.os, b->hinfo.os);
307
308 case DNS_TYPE_A:
322345fd 309 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
2d4c5cbc
LP
310
311 case DNS_TYPE_AAAA:
322345fd 312 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
2d4c5cbc
LP
313
314 case DNS_TYPE_SOA:
7e8e0422
LP
315 r = dns_name_equal(a->soa.mname, b->soa.mname);
316 if (r <= 0)
317 return r;
318 r = dns_name_equal(a->soa.rname, b->soa.rname);
319 if (r <= 0)
320 return r;
321
322 return a->soa.serial == b->soa.serial &&
323 a->soa.refresh == b->soa.refresh &&
324 a->soa.retry == b->soa.retry &&
325 a->soa.expire == b->soa.expire &&
326 a->soa.minimum == b->soa.minimum;
946c7094
ZJS
327 case DNS_TYPE_MX:
328 if (a->mx.priority != b->mx.priority)
329 return 0;
330
331 return dns_name_equal(a->mx.exchange, b->mx.exchange);
332
2d4c5cbc 333 default:
322345fd
LP
334 return a->generic.size == b->generic.size &&
335 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
2d4c5cbc 336 }
322345fd
LP
337}
338
2d4c5cbc
LP
339int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
340 _cleanup_free_ char *k = NULL;
341 char *s;
342 int r;
322345fd 343
2d4c5cbc 344 assert(rr);
322345fd 345
2d4c5cbc
LP
346 r = dns_resource_key_to_string(rr->key, &k);
347 if (r < 0)
348 return r;
322345fd 349
2d4c5cbc 350 switch (rr->key->type) {
322345fd 351
2d4c5cbc
LP
352 case DNS_TYPE_PTR:
353 case DNS_TYPE_NS:
354 case DNS_TYPE_CNAME:
355 s = strjoin(k, " ", rr->ptr.name, NULL);
356 if (!s)
357 return -ENOMEM;
322345fd 358
2d4c5cbc 359 break;
322345fd 360
2d4c5cbc
LP
361 case DNS_TYPE_HINFO:
362 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
363 if (!s)
364 return -ENOMEM;
365 break;
322345fd 366
2d4c5cbc
LP
367 case DNS_TYPE_A: {
368 _cleanup_free_ char *x = NULL;
322345fd 369
2d4c5cbc
LP
370 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
371 if (r < 0)
372 return r;
322345fd 373
2d4c5cbc
LP
374 s = strjoin(k, " ", x, NULL);
375 if (!s)
376 return -ENOMEM;
377 break;
378 }
322345fd 379
2d4c5cbc
LP
380 case DNS_TYPE_AAAA: {
381 _cleanup_free_ char *x = NULL;
322345fd 382
2d4c5cbc
LP
383 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &x);
384 if (r < 0)
385 return r;
322345fd 386
2d4c5cbc
LP
387 s = strjoin(k, " ", x, NULL);
388 if (!s)
389 return -ENOMEM;
390 break;
391 }
322345fd 392
2d4c5cbc
LP
393 case DNS_TYPE_SOA:
394 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
395 k,
396 strna(rr->soa.mname),
397 strna(rr->soa.rname),
398 rr->soa.serial,
399 rr->soa.refresh,
400 rr->soa.retry,
401 rr->soa.expire,
402 rr->soa.minimum);
403 if (r < 0)
404 return -ENOMEM;
405 break;
406
946c7094
ZJS
407 case DNS_TYPE_MX:
408 r = asprintf(&s, "%s %u %s",
409 k,
410 rr->mx.priority,
411 rr->mx.exchange);
412 if (r < 0)
413 return -ENOMEM;
414 break;
415
2d4c5cbc
LP
416 default: {
417 _cleanup_free_ char *x = NULL;
418
419 x = hexmem(rr->generic.data, rr->generic.size);
420 if (!x)
421 return -ENOMEM;
422
423 s = strjoin(k, " ", x, NULL);
424 if (!s)
425 return -ENOMEM;
426 break;
427 }}
428
429 *ret = s;
430 return 0;
431}
322345fd 432
2d4c5cbc 433const char *dns_class_to_string(uint16_t class) {
322345fd 434
2d4c5cbc 435 switch (class) {
322345fd 436
2d4c5cbc
LP
437 case DNS_CLASS_IN:
438 return "IN";
322345fd 439
2d4c5cbc
LP
440 case DNS_CLASS_ANY:
441 return "ANY";
442 }
322345fd 443
2d4c5cbc
LP
444 return NULL;
445}
322345fd 446
2d4c5cbc
LP
447int dns_class_from_string(const char *s, uint16_t *class) {
448 assert(s);
449 assert(class);
450
451 if (strcaseeq(s, "IN"))
452 *class = DNS_CLASS_IN;
453 else if (strcaseeq(s, "ANY"))
454 *class = DNS_TYPE_ANY;
455 else
456 return -EINVAL;
322345fd 457
2d4c5cbc
LP
458 return 0;
459}
322345fd 460
2d4c5cbc
LP
461static const struct {
462 uint16_t type;
463 const char *name;
464} dns_types[] = {
465 { DNS_TYPE_A, "A" },
466 { DNS_TYPE_NS, "NS" },
467 { DNS_TYPE_CNAME, "CNAME" },
468 { DNS_TYPE_SOA, "SOA" },
469 { DNS_TYPE_PTR, "PTR" },
470 { DNS_TYPE_HINFO, "HINFO" },
471 { DNS_TYPE_MX, "MX" },
472 { DNS_TYPE_TXT, "TXT" },
473 { DNS_TYPE_AAAA, "AAAA" },
474 { DNS_TYPE_SRV, "SRV" },
475 { DNS_TYPE_SSHFP, "SSHFP" },
476 { DNS_TYPE_DNAME, "DNAME" },
477 { DNS_TYPE_ANY, "ANY" },
478 { DNS_TYPE_OPT, "OPT" },
479 { DNS_TYPE_TKEY, "TKEY" },
480 { DNS_TYPE_TSIG, "TSIG" },
481 { DNS_TYPE_IXFR, "IXFR" },
482 { DNS_TYPE_AXFR, "AXFR" },
483};
322345fd 484
322345fd 485
2d4c5cbc
LP
486const char *dns_type_to_string(uint16_t type) {
487 unsigned i;
322345fd 488
2d4c5cbc
LP
489 for (i = 0; i < ELEMENTSOF(dns_types); i++)
490 if (dns_types[i].type == type)
491 return dns_types[i].name;
322345fd
LP
492
493 return NULL;
494}
2d4c5cbc
LP
495
496int dns_type_from_string(const char *s, uint16_t *type) {
497 unsigned i;
498
499 assert(s);
500 assert(type);
501
502 for (i = 0; i < ELEMENTSOF(dns_types); i++)
503 if (strcaseeq(dns_types[i].name, s)) {
504 *type = dns_types[i].type;
505 return 0;
506 }
507
508 return -EINVAL;
509}