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