]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-question.c
resolved: rr - introduce dns_resource_key_new_cname()
[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
22#include "resolved-dns-question.h"
4ad7f276 23#include "dns-domain.h"
faa133f3
LP
24
25DnsQuestion *dns_question_new(unsigned n) {
26 DnsQuestion *q;
27
28 assert(n > 0);
29
30 q = malloc0(offsetof(DnsQuestion, keys) + sizeof(DnsResourceKey*) * n);
31 if (!q)
32 return NULL;
33
34 q->n_ref = 1;
35 q->n_allocated = n;
36
37 return q;
38}
39
40DnsQuestion *dns_question_ref(DnsQuestion *q) {
41 if (!q)
42 return NULL;
43
44 assert(q->n_ref > 0);
45 q->n_ref++;
46 return q;
47}
48
49DnsQuestion *dns_question_unref(DnsQuestion *q) {
50 if (!q)
51 return NULL;
52
53 assert(q->n_ref > 0);
54
55 if (q->n_ref == 1) {
56 unsigned i;
57
58 for (i = 0; i < q->n_keys; i++)
59 dns_resource_key_unref(q->keys[i]);
60 free(q);
61 } else
62 q->n_ref--;
63
64 return NULL;
65}
66
67int dns_question_add(DnsQuestion *q, DnsResourceKey *key) {
7e8e0422
LP
68 unsigned i;
69 int r;
70
faa133f3
LP
71 assert(key);
72
8013e860
LP
73 if (!q)
74 return -ENOSPC;
75
7e8e0422
LP
76 for (i = 0; i < q->n_keys; i++) {
77 r = dns_resource_key_equal(q->keys[i], key);
78 if (r < 0)
79 return r;
80 if (r > 0)
81 return 0;
82 }
83
faa133f3
LP
84 if (q->n_keys >= q->n_allocated)
85 return -ENOSPC;
86
87 q->keys[q->n_keys++] = dns_resource_key_ref(key);
88 return 0;
89}
90
91int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr) {
92 unsigned i;
93 int r;
94
faa133f3
LP
95 assert(rr);
96
8013e860
LP
97 if (!q)
98 return 0;
99
faa133f3
LP
100 for (i = 0; i < q->n_keys; i++) {
101 r = dns_resource_key_match_rr(q->keys[i], rr);
102 if (r != 0)
103 return r;
104 }
105
106 return 0;
107}
108
109int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr) {
110 unsigned i;
111 int r;
112
faa133f3
LP
113 assert(rr);
114
8013e860
LP
115 if (!q)
116 return 0;
117
faa133f3
LP
118 for (i = 0; i < q->n_keys; i++) {
119 r = dns_resource_key_match_cname(q->keys[i], rr);
120 if (r != 0)
121 return r;
122 }
123
34b9656f 124 return 0;
faa133f3
LP
125}
126
127int dns_question_is_valid(DnsQuestion *q) {
128 const char *name;
129 unsigned i;
130 int r;
131
8013e860
LP
132 if (!q)
133 return 0;
faa133f3
LP
134
135 if (q->n_keys <= 0)
136 return 0;
137
138 if (q->n_keys > 65535)
139 return 0;
140
141 name = DNS_RESOURCE_KEY_NAME(q->keys[0]);
142 if (!name)
143 return 0;
144
145 /* Check that all keys in this question bear the same name */
146 for (i = 1; i < q->n_keys; i++) {
34b9656f
LP
147 assert(q->keys[i]);
148
faa133f3
LP
149 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name);
150 if (r <= 0)
151 return r;
152 }
153
154 return 1;
155}
156
157int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other) {
158 unsigned j;
159 int r;
160
faa133f3
LP
161 /* Checks if all keys in "other" are also contained in "q" */
162
8013e860
LP
163 if (!other)
164 return 1;
165
faa133f3
LP
166 for (j = 0; j < other->n_keys; j++) {
167 DnsResourceKey *b = other->keys[j];
168 bool found = false;
169 unsigned i;
170
8013e860
LP
171 if (!q)
172 return 0;
173
faa133f3
LP
174 for (i = 0; i < q->n_keys; i++) {
175 DnsResourceKey *a = q->keys[i];
176
177 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
178 if (r < 0)
179 return r;
180
181 if (r == 0)
182 continue;
183
184 if (a->class != b->class && a->class != DNS_CLASS_ANY)
185 continue;
186
187 if (a->type != b->type && a->type != DNS_TYPE_ANY)
188 continue;
189
190 found = true;
191 break;
192 }
193
194 if (!found)
195 return 0;
196 }
197
198 return 1;
199}
200
1086182d
LP
201int dns_question_contains(DnsQuestion *a, DnsResourceKey *k) {
202 unsigned j;
203 int r;
204
1086182d
LP
205 assert(k);
206
8013e860
LP
207 if (!a)
208 return 0;
209
1086182d
LP
210 for (j = 0; j < a->n_keys; j++) {
211 r = dns_resource_key_equal(a->keys[j], k);
212 if (r != 0)
213 return r;
214 }
215
216 return 0;
217}
218
219int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b) {
220 unsigned j;
221 int r;
222
8013e860
LP
223 if (!a)
224 return !b || b->n_keys == 0;
225 if (!b)
226 return a->n_keys == 0;
1086182d
LP
227
228 /* Checks if all keys in a are also contained b, and vice versa */
229
230 for (j = 0; j < a->n_keys; j++) {
231 r = dns_question_contains(b, a->keys[j]);
232 if (r <= 0)
233 return r;
234 }
235
236 for (j = 0; j < b->n_keys; j++) {
237 r = dns_question_contains(a, b->keys[j]);
238 if (r <= 0)
239 return r;
240 }
241
242 return 1;
243}
244
faa133f3
LP
245int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **ret) {
246 _cleanup_(dns_question_unrefp) DnsQuestion *n = NULL;
247 bool same = true;
248 unsigned i;
249 int r;
250
faa133f3
LP
251 assert(name);
252 assert(ret);
253
8013e860
LP
254 if (!q) {
255 n = dns_question_new(0);
256 if (!n)
257 return -ENOMEM;
258
259 *ret = n;
260 n = 0;
261 return 0;
262 }
263
faa133f3
LP
264 for (i = 0; i < q->n_keys; i++) {
265 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name);
266 if (r < 0)
267 return r;
268
269 if (r == 0) {
270 same = false;
271 break;
272 }
273 }
274
275 if (same) {
276 /* Shortcut, the names are already right */
277 *ret = dns_question_ref(q);
278 return 0;
279 }
280
281 n = dns_question_new(q->n_keys);
282 if (!n)
283 return -ENOMEM;
284
285 /* Create a new question, and patch in the new name */
34b9656f 286 for (i = 0; i < q->n_keys; i++) {
faa133f3
LP
287 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
288
289 k = dns_resource_key_new(q->keys[i]->class, q->keys[i]->type, name);
290 if (!k)
291 return -ENOMEM;
292
293 r = dns_question_add(n, k);
294 if (r < 0)
295 return r;
296 }
297
298 *ret = n;
299 n = NULL;
300
301 return 1;
302}