]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-question.c
Merge pull request #2024 from eworm-de/net
[thirdparty/systemd.git] / src / resolve / resolved-dns-question.c
CommitLineData
faa133f3
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
b5efdb8a 22#include "alloc-util.h"
4ad7f276 23#include "dns-domain.h"
b5efdb8a 24#include "resolved-dns-question.h"
faa133f3
LP
25
26DnsQuestion *dns_question_new(unsigned n) {
27 DnsQuestion *q;
28
29 assert(n > 0);
30
31 q = malloc0(offsetof(DnsQuestion, keys) + sizeof(DnsResourceKey*) * n);
32 if (!q)
33 return NULL;
34
35 q->n_ref = 1;
36 q->n_allocated = n;
37
38 return q;
39}
40
41DnsQuestion *dns_question_ref(DnsQuestion *q) {
42 if (!q)
43 return NULL;
44
45 assert(q->n_ref > 0);
46 q->n_ref++;
47 return q;
48}
49
50DnsQuestion *dns_question_unref(DnsQuestion *q) {
51 if (!q)
52 return NULL;
53
54 assert(q->n_ref > 0);
55
56 if (q->n_ref == 1) {
57 unsigned i;
58
59 for (i = 0; i < q->n_keys; i++)
60 dns_resource_key_unref(q->keys[i]);
61 free(q);
62 } else
63 q->n_ref--;
64
65 return NULL;
66}
67
68int dns_question_add(DnsQuestion *q, DnsResourceKey *key) {
7e8e0422
LP
69 unsigned i;
70 int r;
71
faa133f3
LP
72 assert(key);
73
8013e860
LP
74 if (!q)
75 return -ENOSPC;
76
7e8e0422
LP
77 for (i = 0; i < q->n_keys; i++) {
78 r = dns_resource_key_equal(q->keys[i], key);
79 if (r < 0)
80 return r;
81 if (r > 0)
82 return 0;
83 }
84
faa133f3
LP
85 if (q->n_keys >= q->n_allocated)
86 return -ENOSPC;
87
88 q->keys[q->n_keys++] = dns_resource_key_ref(key);
89 return 0;
90}
91
92int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr) {
93 unsigned i;
94 int r;
95
faa133f3
LP
96 assert(rr);
97
8013e860
LP
98 if (!q)
99 return 0;
100
faa133f3
LP
101 for (i = 0; i < q->n_keys; i++) {
102 r = dns_resource_key_match_rr(q->keys[i], rr);
103 if (r != 0)
104 return r;
105 }
106
107 return 0;
108}
109
110int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr) {
111 unsigned i;
112 int r;
113
faa133f3
LP
114 assert(rr);
115
8013e860
LP
116 if (!q)
117 return 0;
118
faa133f3
LP
119 for (i = 0; i < q->n_keys; i++) {
120 r = dns_resource_key_match_cname(q->keys[i], rr);
121 if (r != 0)
122 return r;
123 }
124
34b9656f 125 return 0;
faa133f3
LP
126}
127
128int dns_question_is_valid(DnsQuestion *q) {
129 const char *name;
130 unsigned i;
131 int r;
132
8013e860
LP
133 if (!q)
134 return 0;
faa133f3
LP
135
136 if (q->n_keys <= 0)
137 return 0;
138
139 if (q->n_keys > 65535)
140 return 0;
141
142 name = DNS_RESOURCE_KEY_NAME(q->keys[0]);
143 if (!name)
144 return 0;
145
146 /* Check that all keys in this question bear the same name */
147 for (i = 1; i < q->n_keys; i++) {
34b9656f
LP
148 assert(q->keys[i]);
149
faa133f3
LP
150 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name);
151 if (r <= 0)
152 return r;
153 }
154
155 return 1;
156}
157
1086182d
LP
158int dns_question_contains(DnsQuestion *a, DnsResourceKey *k) {
159 unsigned j;
160 int r;
161
1086182d
LP
162 assert(k);
163
8013e860
LP
164 if (!a)
165 return 0;
166
1086182d
LP
167 for (j = 0; j < a->n_keys; j++) {
168 r = dns_resource_key_equal(a->keys[j], k);
169 if (r != 0)
170 return r;
171 }
172
173 return 0;
174}
175
176int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b) {
177 unsigned j;
178 int r;
179
8013e860
LP
180 if (!a)
181 return !b || b->n_keys == 0;
182 if (!b)
183 return a->n_keys == 0;
1086182d
LP
184
185 /* Checks if all keys in a are also contained b, and vice versa */
186
187 for (j = 0; j < a->n_keys; j++) {
188 r = dns_question_contains(b, a->keys[j]);
189 if (r <= 0)
190 return r;
191 }
192
193 for (j = 0; j < b->n_keys; j++) {
194 r = dns_question_contains(a, b->keys[j]);
195 if (r <= 0)
196 return r;
197 }
198
199 return 1;
200}
201
36d9205d 202int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, DnsQuestion **ret) {
faa133f3
LP
203 _cleanup_(dns_question_unrefp) DnsQuestion *n = NULL;
204 bool same = true;
205 unsigned i;
206 int r;
207
36d9205d 208 assert(cname);
faa133f3 209 assert(ret);
58db254a 210 assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME));
faa133f3 211
8013e860
LP
212 if (!q) {
213 n = dns_question_new(0);
214 if (!n)
215 return -ENOMEM;
216
217 *ret = n;
218 n = 0;
219 return 0;
220 }
221
faa133f3 222 for (i = 0; i < q->n_keys; i++) {
58db254a
LP
223 _cleanup_free_ char *destination = NULL;
224 const char *d;
225
226 if (cname->key->type == DNS_TYPE_CNAME)
227 d = cname->cname.name;
228 else {
229 r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(q->keys[i]), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination);
230 if (r < 0)
231 return r;
232 if (r == 0)
233 continue;
234
235 d = destination;
236 }
237
238 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), d);
faa133f3
LP
239 if (r < 0)
240 return r;
241
242 if (r == 0) {
243 same = false;
244 break;
245 }
246 }
247
248 if (same) {
249 /* Shortcut, the names are already right */
250 *ret = dns_question_ref(q);
251 return 0;
252 }
253
254 n = dns_question_new(q->n_keys);
255 if (!n)
256 return -ENOMEM;
257
258 /* Create a new question, and patch in the new name */
34b9656f 259 for (i = 0; i < q->n_keys; i++) {
faa133f3
LP
260 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
261
36d9205d 262 k = dns_resource_key_new_redirect(q->keys[i], cname);
faa133f3
LP
263 if (!k)
264 return -ENOMEM;
265
266 r = dns_question_add(n, k);
267 if (r < 0)
268 return r;
269 }
270
271 *ret = n;
272 n = NULL;
273
274 return 1;
275}
45ec7efb
LP
276
277const char *dns_question_name(DnsQuestion *q) {
278 assert(q);
279
280 if (q->n_keys < 1)
281 return NULL;
282
283 return DNS_RESOURCE_KEY_NAME(q->keys[0]);
284}
285
286int dns_question_new_address(DnsQuestion **ret, int family, const char *name) {
287 _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL;
288 int r;
289
290 assert(ret);
291 assert(name);
292
293 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
294 return -EAFNOSUPPORT;
295
296 q = dns_question_new(family == AF_UNSPEC ? 2 : 1);
297 if (!q)
298 return -ENOMEM;
299
300 if (family != AF_INET6) {
301 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
302
303 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, name);
304 if (!key)
305 return -ENOMEM;
306
307 r = dns_question_add(q, key);
308 if (r < 0)
309 return r;
310 }
311
312 if (family != AF_INET) {
313 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
314
315 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
316 if (!key)
317 return -ENOMEM;
318
319 r = dns_question_add(q, key);
320 if (r < 0)
321 return r;
322 }
323
324 *ret = q;
325 q = NULL;
326
327 return 0;
328}
329
330int dns_question_new_reverse(DnsQuestion **ret, int family, const union in_addr_union *a) {
331 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
332 _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL;
333 _cleanup_free_ char *reverse = NULL;
334 int r;
335
336 assert(ret);
337 assert(a);
338
339 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
340 return -EAFNOSUPPORT;
341
342 r = dns_name_reverse(family, a, &reverse);
343 if (r < 0)
344 return r;
345
346 q = dns_question_new(1);
347 if (!q)
348 return -ENOMEM;
349
350 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse);
351 if (!key)
352 return -ENOMEM;
353
354 reverse = NULL;
355
356 r = dns_question_add(q, key);
357 if (r < 0)
358 return r;
359
360 *ret = q;
361 q = NULL;
362
363 return 0;
364}
365
366int dns_question_new_service(DnsQuestion **ret, const char *name, bool with_txt) {
367 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
368 _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL;
369 int r;
370
371 assert(ret);
372 assert(name);
373
374 q = dns_question_new(1 + with_txt);
375 if (!q)
376 return -ENOMEM;
377
378 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_SRV, name);
379 if (!key)
380 return -ENOMEM;
381
382 r = dns_question_add(q, key);
383 if (r < 0)
384 return r;
385
386 if (with_txt) {
387 dns_resource_key_unref(key);
388 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_TXT, name);
389 if (!key)
390 return -ENOMEM;
391
392 r = dns_question_add(q, key);
393 if (r < 0)
394 return r;
395 }
396
397 *ret = q;
398 q = NULL;
399
400 return 0;
401}