]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-question.c
resolved: rework logic so that we can share transactions between queries of different...
[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"
23#include "resolved-dns-domain.h"
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) {
68 assert(q);
69 assert(key);
70
71 if (q->n_keys >= q->n_allocated)
72 return -ENOSPC;
73
74 q->keys[q->n_keys++] = dns_resource_key_ref(key);
75 return 0;
76}
77
78int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr) {
79 unsigned i;
80 int r;
81
82 assert(q);
83 assert(rr);
84
85 for (i = 0; i < q->n_keys; i++) {
86 r = dns_resource_key_match_rr(q->keys[i], rr);
87 if (r != 0)
88 return r;
89 }
90
91 return 0;
92}
93
94int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr) {
95 unsigned i;
96 int r;
97
98 assert(q);
99 assert(rr);
100
101 for (i = 0; i < q->n_keys; i++) {
102 r = dns_resource_key_match_cname(q->keys[i], rr);
103 if (r != 0)
104 return r;
105 }
106
107 return 1;
108}
109
110int dns_question_is_valid(DnsQuestion *q) {
111 const char *name;
112 unsigned i;
113 int r;
114
115 assert(q);
116
117 if (q->n_keys <= 0)
118 return 0;
119
120 if (q->n_keys > 65535)
121 return 0;
122
123 name = DNS_RESOURCE_KEY_NAME(q->keys[0]);
124 if (!name)
125 return 0;
126
127 /* Check that all keys in this question bear the same name */
128 for (i = 1; i < q->n_keys; i++) {
129 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name);
130 if (r <= 0)
131 return r;
132 }
133
134 return 1;
135}
136
137int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other) {
138 unsigned j;
139 int r;
140
141 assert(q);
142 assert(other);
143
144 /* Checks if all keys in "other" are also contained in "q" */
145
146 for (j = 0; j < other->n_keys; j++) {
147 DnsResourceKey *b = other->keys[j];
148 bool found = false;
149 unsigned i;
150
151 for (i = 0; i < q->n_keys; i++) {
152 DnsResourceKey *a = q->keys[i];
153
154 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
155 if (r < 0)
156 return r;
157
158 if (r == 0)
159 continue;
160
161 if (a->class != b->class && a->class != DNS_CLASS_ANY)
162 continue;
163
164 if (a->type != b->type && a->type != DNS_TYPE_ANY)
165 continue;
166
167 found = true;
168 break;
169 }
170
171 if (!found)
172 return 0;
173 }
174
175 return 1;
176}
177
178int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **ret) {
179 _cleanup_(dns_question_unrefp) DnsQuestion *n = NULL;
180 bool same = true;
181 unsigned i;
182 int r;
183
184 assert(q);
185 assert(name);
186 assert(ret);
187
188 for (i = 0; i < q->n_keys; i++) {
189 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name);
190 if (r < 0)
191 return r;
192
193 if (r == 0) {
194 same = false;
195 break;
196 }
197 }
198
199 if (same) {
200 /* Shortcut, the names are already right */
201 *ret = dns_question_ref(q);
202 return 0;
203 }
204
205 n = dns_question_new(q->n_keys);
206 if (!n)
207 return -ENOMEM;
208
209 /* Create a new question, and patch in the new name */
210 for (n->n_keys = 0; n->n_keys < q->n_keys; n->n_keys++) {
211 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
212
213 k = dns_resource_key_new(q->keys[i]->class, q->keys[i]->type, name);
214 if (!k)
215 return -ENOMEM;
216
217 r = dns_question_add(n, k);
218 if (r < 0)
219 return r;
220 }
221
222 *ret = n;
223 n = NULL;
224
225 return 1;
226}