]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-question.c
resolved: rr - introduce dns_resource_key_new_redirect()
[thirdparty/systemd.git] / src / resolve / resolved-dns-question.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-question.h"
23 #include "dns-domain.h"
24
25 DnsQuestion *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
40 DnsQuestion *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
49 DnsQuestion *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
67 int dns_question_add(DnsQuestion *q, DnsResourceKey *key) {
68 unsigned i;
69 int r;
70
71 assert(key);
72
73 if (!q)
74 return -ENOSPC;
75
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
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
91 int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr) {
92 unsigned i;
93 int r;
94
95 assert(rr);
96
97 if (!q)
98 return 0;
99
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
109 int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr) {
110 unsigned i;
111 int r;
112
113 assert(rr);
114
115 if (!q)
116 return 0;
117
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
124 return 0;
125 }
126
127 int dns_question_is_valid(DnsQuestion *q) {
128 const char *name;
129 unsigned i;
130 int r;
131
132 if (!q)
133 return 0;
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++) {
147 assert(q->keys[i]);
148
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
157 int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other) {
158 unsigned j;
159 int r;
160
161 /* Checks if all keys in "other" are also contained in "q" */
162
163 if (!other)
164 return 1;
165
166 for (j = 0; j < other->n_keys; j++) {
167 DnsResourceKey *b = other->keys[j];
168 bool found = false;
169 unsigned i;
170
171 if (!q)
172 return 0;
173
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
201 int dns_question_contains(DnsQuestion *a, DnsResourceKey *k) {
202 unsigned j;
203 int r;
204
205 assert(k);
206
207 if (!a)
208 return 0;
209
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
219 int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b) {
220 unsigned j;
221 int r;
222
223 if (!a)
224 return !b || b->n_keys == 0;
225 if (!b)
226 return a->n_keys == 0;
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
245 int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, DnsQuestion **ret) {
246 _cleanup_(dns_question_unrefp) DnsQuestion *n = NULL;
247 bool same = true;
248 unsigned i;
249 int r;
250
251 assert(cname);
252 assert(ret);
253
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
264 for (i = 0; i < q->n_keys; i++) {
265 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), cname->cname.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 */
286 for (i = 0; i < q->n_keys; i++) {
287 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
288
289 k = dns_resource_key_new_redirect(q->keys[i], cname);
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 }