chiark / gitweb /
resolve: add more record types and convert to gperf table
[elogind.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 0;
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                 assert(q->keys[i]);
141
142                 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name);
143                 if (r <= 0)
144                         return r;
145         }
146
147         return 1;
148 }
149
150 int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other) {
151         unsigned j;
152         int r;
153
154         assert(q);
155         assert(other);
156
157         /* Checks if all keys in "other" are also contained in "q" */
158
159         for (j = 0; j < other->n_keys; j++) {
160                 DnsResourceKey *b = other->keys[j];
161                 bool found = false;
162                 unsigned i;
163
164                 for (i = 0; i < q->n_keys; i++) {
165                         DnsResourceKey *a = q->keys[i];
166
167                         r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
168                         if (r < 0)
169                                 return r;
170
171                         if (r == 0)
172                                 continue;
173
174                         if (a->class != b->class && a->class != DNS_CLASS_ANY)
175                                 continue;
176
177                         if (a->type != b->type && a->type != DNS_TYPE_ANY)
178                                 continue;
179
180                         found = true;
181                         break;
182                 }
183
184                 if (!found)
185                         return 0;
186         }
187
188         return 1;
189 }
190
191 int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **ret) {
192         _cleanup_(dns_question_unrefp) DnsQuestion *n = NULL;
193         bool same = true;
194         unsigned i;
195         int r;
196
197         assert(q);
198         assert(name);
199         assert(ret);
200
201         for (i = 0; i < q->n_keys; i++) {
202                 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name);
203                 if (r < 0)
204                         return r;
205
206                 if (r == 0) {
207                         same = false;
208                         break;
209                 }
210         }
211
212         if (same) {
213                 /* Shortcut, the names are already right */
214                 *ret = dns_question_ref(q);
215                 return 0;
216         }
217
218         n = dns_question_new(q->n_keys);
219         if (!n)
220                 return -ENOMEM;
221
222         /* Create a new question, and patch in the new name */
223         for (i = 0; i < q->n_keys; i++) {
224                 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
225
226                 k = dns_resource_key_new(q->keys[i]->class, q->keys[i]->type, name);
227                 if (!k)
228                         return -ENOMEM;
229
230                 r = dns_question_add(n, k);
231                 if (r < 0)
232                         return r;
233         }
234
235         *ret = n;
236         n = NULL;
237
238         return 1;
239 }
240
241 int dns_question_endswith(DnsQuestion *q, const char *suffix) {
242         unsigned i;
243
244         assert(q);
245         assert(suffix);
246
247         for (i = 0; i < q->n_keys; i++) {
248                 int k;
249
250                 k = dns_name_endswith(DNS_RESOURCE_KEY_NAME(q->keys[i]), suffix);
251                 if (k <= 0)
252                         return k;
253         }
254
255         return 1;
256 }
257
258 int dns_question_extract_reverse_address(DnsQuestion *q, int *family, union in_addr_union *address) {
259         unsigned i;
260
261         assert(q);
262         assert(family);
263         assert(address);
264
265         for (i = 0; i < q->n_keys; i++) {
266                 int k;
267
268                 k = dns_name_address(DNS_RESOURCE_KEY_NAME(q->keys[i]), family, address);
269                 if (k != 0)
270                         return k;
271         }
272
273         return 0;
274 }