]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-question.c
resolved: set LLMNR TCP and UDP TTLs to the values suggested by the RFC
[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 "resolved-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(q);
72 assert(key);
73
74 for (i = 0; i < q->n_keys; i++) {
75 r = dns_resource_key_equal(q->keys[i], key);
76 if (r < 0)
77 return r;
78 if (r > 0)
79 return 0;
80 }
81
82 if (q->n_keys >= q->n_allocated)
83 return -ENOSPC;
84
85 q->keys[q->n_keys++] = dns_resource_key_ref(key);
86 return 0;
87 }
88
89 int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr) {
90 unsigned i;
91 int r;
92
93 assert(q);
94 assert(rr);
95
96 for (i = 0; i < q->n_keys; i++) {
97 r = dns_resource_key_match_rr(q->keys[i], rr);
98 if (r != 0)
99 return r;
100 }
101
102 return 0;
103 }
104
105 int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr) {
106 unsigned i;
107 int r;
108
109 assert(q);
110 assert(rr);
111
112 for (i = 0; i < q->n_keys; i++) {
113 r = dns_resource_key_match_cname(q->keys[i], rr);
114 if (r != 0)
115 return r;
116 }
117
118 return 1;
119 }
120
121 int dns_question_is_valid(DnsQuestion *q) {
122 const char *name;
123 unsigned i;
124 int r;
125
126 assert(q);
127
128 if (q->n_keys <= 0)
129 return 0;
130
131 if (q->n_keys > 65535)
132 return 0;
133
134 name = DNS_RESOURCE_KEY_NAME(q->keys[0]);
135 if (!name)
136 return 0;
137
138 /* Check that all keys in this question bear the same name */
139 for (i = 1; i < q->n_keys; i++) {
140 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name);
141 if (r <= 0)
142 return r;
143 }
144
145 return 1;
146 }
147
148 int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other) {
149 unsigned j;
150 int r;
151
152 assert(q);
153 assert(other);
154
155 /* Checks if all keys in "other" are also contained in "q" */
156
157 for (j = 0; j < other->n_keys; j++) {
158 DnsResourceKey *b = other->keys[j];
159 bool found = false;
160 unsigned i;
161
162 for (i = 0; i < q->n_keys; i++) {
163 DnsResourceKey *a = q->keys[i];
164
165 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
166 if (r < 0)
167 return r;
168
169 if (r == 0)
170 continue;
171
172 if (a->class != b->class && a->class != DNS_CLASS_ANY)
173 continue;
174
175 if (a->type != b->type && a->type != DNS_TYPE_ANY)
176 continue;
177
178 found = true;
179 break;
180 }
181
182 if (!found)
183 return 0;
184 }
185
186 return 1;
187 }
188
189 int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **ret) {
190 _cleanup_(dns_question_unrefp) DnsQuestion *n = NULL;
191 bool same = true;
192 unsigned i;
193 int r;
194
195 assert(q);
196 assert(name);
197 assert(ret);
198
199 for (i = 0; i < q->n_keys; i++) {
200 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name);
201 if (r < 0)
202 return r;
203
204 if (r == 0) {
205 same = false;
206 break;
207 }
208 }
209
210 if (same) {
211 /* Shortcut, the names are already right */
212 *ret = dns_question_ref(q);
213 return 0;
214 }
215
216 n = dns_question_new(q->n_keys);
217 if (!n)
218 return -ENOMEM;
219
220 /* Create a new question, and patch in the new name */
221 for (n->n_keys = 0; n->n_keys < q->n_keys; n->n_keys++) {
222 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
223
224 k = dns_resource_key_new(q->keys[i]->class, q->keys[i]->type, name);
225 if (!k)
226 return -ENOMEM;
227
228 r = dns_question_add(n, k);
229 if (r < 0)
230 return r;
231 }
232
233 *ret = n;
234 n = NULL;
235
236 return 1;
237 }
238
239 int dns_question_endswith(DnsQuestion *q, const char *suffix) {
240 unsigned i;
241
242 assert(q);
243 assert(suffix);
244
245 for (i = 0; i < q->n_keys; i++) {
246 int k;
247
248 k = dns_name_endswith(DNS_RESOURCE_KEY_NAME(q->keys[i]), suffix);
249 if (k <= 0)
250 return k;
251 }
252
253 return 1;
254 }
255
256 int dns_question_extract_reverse_address(DnsQuestion *q, int *family, union in_addr_union *address) {
257 unsigned i;
258
259 assert(q);
260 assert(family);
261 assert(address);
262
263 for (i = 0; i < q->n_keys; i++) {
264 int k;
265
266 k = dns_name_address(DNS_RESOURCE_KEY_NAME(q->keys[i]), family, address);
267 if (k != 0)
268 return k;
269 }
270
271 return 0;
272 }