]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-question.c
resolved: make key argument of dns_question_contains() const
[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
801ad6a6 92int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) {
faa133f3
LP
93 unsigned i;
94 int r;
95
faa133f3
LP
96 assert(rr);
97
8013e860
LP
98 if (!q)
99 return 0;
100
faa133f3 101 for (i = 0; i < q->n_keys; i++) {
801ad6a6 102 r = dns_resource_key_match_rr(q->keys[i], rr, search_domain);
faa133f3
LP
103 if (r != 0)
104 return r;
105 }
106
107 return 0;
108}
109
801ad6a6 110int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) {
faa133f3
LP
111 unsigned i;
112 int r;
113
faa133f3
LP
114 assert(rr);
115
8013e860
LP
116 if (!q)
117 return 0;
118
faa133f3 119 for (i = 0; i < q->n_keys; i++) {
5d27351f 120 r = dns_resource_key_match_cname_or_dname(q->keys[i], rr->key, search_domain);
faa133f3
LP
121 if (r != 0)
122 return r;
123 }
124
34b9656f 125 return 0;
faa133f3
LP
126}
127
703e4f5e 128int dns_question_is_valid_for_query(DnsQuestion *q) {
faa133f3
LP
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
6a21960c 158int dns_question_contains(DnsQuestion *a, const DnsResourceKey *k) {
1086182d
LP
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 276
703e4f5e
LP
277const char *dns_question_first_name(DnsQuestion *q) {
278
279 if (!q)
280 return NULL;
45ec7efb
LP
281
282 if (q->n_keys < 1)
283 return NULL;
284
285 return DNS_RESOURCE_KEY_NAME(q->keys[0]);
286}
287
288int dns_question_new_address(DnsQuestion **ret, int family, const char *name) {
289 _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL;
290 int r;
291
292 assert(ret);
293 assert(name);
294
295 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
296 return -EAFNOSUPPORT;
297
298 q = dns_question_new(family == AF_UNSPEC ? 2 : 1);
299 if (!q)
300 return -ENOMEM;
301
302 if (family != AF_INET6) {
303 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
304
305 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, name);
306 if (!key)
307 return -ENOMEM;
308
309 r = dns_question_add(q, key);
310 if (r < 0)
311 return r;
312 }
313
314 if (family != AF_INET) {
315 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
316
317 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
318 if (!key)
319 return -ENOMEM;
320
321 r = dns_question_add(q, key);
322 if (r < 0)
323 return r;
324 }
325
326 *ret = q;
327 q = NULL;
328
329 return 0;
330}
331
332int dns_question_new_reverse(DnsQuestion **ret, int family, const union in_addr_union *a) {
333 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
334 _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL;
335 _cleanup_free_ char *reverse = NULL;
336 int r;
337
338 assert(ret);
339 assert(a);
340
341 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
342 return -EAFNOSUPPORT;
343
344 r = dns_name_reverse(family, a, &reverse);
345 if (r < 0)
346 return r;
347
348 q = dns_question_new(1);
349 if (!q)
350 return -ENOMEM;
351
352 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse);
353 if (!key)
354 return -ENOMEM;
355
356 reverse = NULL;
357
358 r = dns_question_add(q, key);
359 if (r < 0)
360 return r;
361
362 *ret = q;
363 q = NULL;
364
365 return 0;
366}
367
368int dns_question_new_service(DnsQuestion **ret, const char *name, bool with_txt) {
369 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
370 _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL;
371 int r;
372
373 assert(ret);
374 assert(name);
375
376 q = dns_question_new(1 + with_txt);
377 if (!q)
378 return -ENOMEM;
379
380 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_SRV, name);
381 if (!key)
382 return -ENOMEM;
383
384 r = dns_question_add(q, key);
385 if (r < 0)
386 return r;
387
388 if (with_txt) {
389 dns_resource_key_unref(key);
390 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_TXT, name);
391 if (!key)
392 return -ENOMEM;
393
394 r = dns_question_add(q, key);
395 if (r < 0)
396 return r;
397 }
398
399 *ret = q;
400 q = NULL;
401
402 return 0;
403}