chiark / gitweb /
resolved: include SOA records in LLMNR replies for non-existing RRs to allow negative...
[elogind.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 DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
163         DnsResourceRecord *rr;
164
165         rr = new0(DnsResourceRecord, 1);
166         if (!rr)
167                 return NULL;
168
169         rr->n_ref = 1;
170         rr->key = dns_resource_key_ref(key);
171
172         return rr;
173 }
174
175 DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
176         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
177
178         key = dns_resource_key_new(class, type, name);
179         if (!key)
180                 return NULL;
181
182         return dns_resource_record_new(key);
183 }
184
185 DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
186         if (!rr)
187                 return NULL;
188
189         assert(rr->n_ref > 0);
190         rr->n_ref++;
191
192         return rr;
193 }
194
195 DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
196         if (!rr)
197                 return NULL;
198
199         assert(rr->n_ref > 0);
200
201         if (rr->n_ref > 1) {
202                 rr->n_ref--;
203                 return NULL;
204         }
205
206         if (rr->key) {
207                 if (IN_SET(rr->key->type, DNS_TYPE_PTR, DNS_TYPE_NS, DNS_TYPE_CNAME))
208                         free(rr->ptr.name);
209                 else if (rr->key->type == DNS_TYPE_HINFO) {
210                         free(rr->hinfo.cpu);
211                         free(rr->hinfo.os);
212                 } else if (rr->key->type == DNS_TYPE_SOA) {
213                         free(rr->soa.mname);
214                         free(rr->soa.rname);
215                 } else if (!IN_SET(rr->key->type, DNS_TYPE_A, DNS_TYPE_AAAA))
216                         free(rr->generic.data);
217
218                 dns_resource_key_unref(rr->key);
219         }
220
221         free(rr);
222
223         return NULL;
224 }
225
226 int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
227         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
228         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
229         _cleanup_free_ char *ptr = NULL;
230         int r;
231
232         assert(ret);
233         assert(address);
234         assert(hostname);
235
236         r = dns_name_reverse(family, address, &ptr);
237         if (r < 0)
238                 return r;
239
240         key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
241         if (!key)
242                 return -ENOMEM;
243
244         ptr = NULL;
245
246         rr = dns_resource_record_new(key);
247         if (!rr)
248                 return -ENOMEM;
249
250         rr->ptr.name = strdup(hostname);
251         if (!rr->ptr.name)
252                 return -ENOMEM;
253
254         *ret = rr;
255         rr = NULL;
256
257         return 0;
258 }
259
260 int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
261         int r;
262
263         assert(a);
264         assert(b);
265
266         r = dns_resource_key_equal(a->key, b->key);
267         if (r <= 0)
268                 return r;
269
270         if (IN_SET(a->key->type, DNS_TYPE_PTR, DNS_TYPE_NS, DNS_TYPE_CNAME))
271                 return dns_name_equal(a->ptr.name, b->ptr.name);
272         else if (a->key->type == DNS_TYPE_HINFO)
273                 return strcasecmp(a->hinfo.cpu, b->hinfo.cpu) == 0 &&
274                        strcasecmp(a->hinfo.os, b->hinfo.os) == 0;
275         else if (a->key->type == DNS_TYPE_A)
276                 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
277         else if (a->key->type == DNS_TYPE_AAAA)
278                 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
279         else if (a->key->type == DNS_TYPE_SOA) {
280                 r = dns_name_equal(a->soa.mname, b->soa.mname);
281                 if (r <= 0)
282                         return r;
283                 r = dns_name_equal(a->soa.rname, b->soa.rname);
284                 if (r <= 0)
285                         return r;
286
287                 return a->soa.serial  == b->soa.serial &&
288                        a->soa.refresh == b->soa.refresh &&
289                        a->soa.retry   == b->soa.retry &&
290                        a->soa.expire  == b->soa.expire &&
291                        a->soa.minimum == b->soa.minimum;
292         } else
293                 return a->generic.size == b->generic.size &&
294                         memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
295 }
296
297 const char *dns_class_to_string(uint16_t class) {
298
299         switch (class) {
300
301         case DNS_CLASS_IN:
302                 return "IN";
303
304         case DNS_CLASS_ANY:
305                 return "ANY";
306         }
307
308         return NULL;
309 }
310
311 const char *dns_type_to_string(uint16_t type) {
312
313         switch (type) {
314
315         case DNS_TYPE_A:
316                 return "A";
317
318         case DNS_TYPE_NS:
319                 return "NS";
320
321         case DNS_TYPE_CNAME:
322                 return "CNAME";
323
324         case DNS_TYPE_SOA:
325                 return "SOA";
326
327         case DNS_TYPE_PTR:
328                 return "PTR";
329
330         case DNS_TYPE_HINFO:
331                 return "HINFO";
332
333         case DNS_TYPE_MX:
334                 return "MX";
335
336         case DNS_TYPE_TXT:
337                 return "TXT";
338
339         case DNS_TYPE_AAAA:
340                 return "AAAA";
341
342         case DNS_TYPE_SRV:
343                 return "SRV";
344
345         case DNS_TYPE_SSHFP:
346                 return "SSHFP";
347
348         case DNS_TYPE_DNAME:
349                 return "DNAME";
350
351         case DNS_TYPE_ANY:
352                 return "ANY";
353
354         case DNS_TYPE_OPT:
355                 return "OPT";
356
357         case DNS_TYPE_TKEY:
358                 return "TKEY";
359
360         case DNS_TYPE_TSIG:
361                 return "TSIG";
362
363         case DNS_TYPE_IXFR:
364                 return "IXFR";
365
366         case DNS_TYPE_AXFR:
367                 return "AXFR";
368         }
369
370         return NULL;
371 }