]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-zone.c
resolved: don't accept messages with ANY RRs
[thirdparty/systemd.git] / src / resolve / resolved-dns-zone.c
CommitLineData
623a4c97
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 "list.h"
23
24#include "resolved-dns-zone.h"
25#include "resolved-dns-domain.h"
26#include "resolved-dns-packet.h"
27
28/* Never allow more than 1K entries */
29#define ZONE_MAX 1024
30
31typedef struct DnsZoneItem DnsZoneItem;
32
33struct DnsZoneItem {
34 DnsResourceRecord *rr;
35 bool verified;
36 LIST_FIELDS(DnsZoneItem, by_key);
37 LIST_FIELDS(DnsZoneItem, by_name);
38};
39
40static void dns_zone_item_free(DnsZoneItem *i) {
41 if (!i)
42 return;
43
44 dns_resource_record_unref(i->rr);
45 free(i);
46}
47
48DEFINE_TRIVIAL_CLEANUP_FUNC(DnsZoneItem*, dns_zone_item_free);
49
50static void dns_zone_item_remove_and_free(DnsZone *z, DnsZoneItem *i) {
51 DnsZoneItem *first;
52
53 assert(z);
54
55 if (!i)
56 return;
57
58 first = hashmap_get(z->by_key, i->rr->key);
59 LIST_REMOVE(by_key, first, i);
60 if (first)
61 assert_se(hashmap_replace(z->by_key, first->rr->key, first) >= 0);
62 else
63 hashmap_remove(z->by_key, i->rr->key);
64
65 first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key));
66 LIST_REMOVE(by_name, first, i);
67 if (first)
68 assert_se(hashmap_replace(z->by_name, DNS_RESOURCE_KEY_NAME(first->rr->key), first) >= 0);
69 else
70 hashmap_remove(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key));
71
72 dns_zone_item_free(i);
73}
74
75void dns_zone_flush(DnsZone *z) {
76 DnsZoneItem *i;
77
78 assert(z);
79
80 while ((i = hashmap_first(z->by_key)))
81 dns_zone_item_remove_and_free(z, i);
82
83 assert(hashmap_size(z->by_key) == 0);
84 assert(hashmap_size(z->by_name) == 0);
85
86 hashmap_free(z->by_key);
87 z->by_key = NULL;
88
89 hashmap_free(z->by_name);
90 z->by_name = NULL;
91}
92
93static DnsZoneItem* dns_zone_get(DnsZone *z, DnsResourceRecord *rr) {
94 DnsZoneItem *i;
95
96 assert(z);
97 assert(rr);
98
99 LIST_FOREACH(by_key, i, hashmap_get(z->by_key, rr->key))
100 if (dns_resource_record_equal(i->rr, rr))
101 return i;
102
103 return NULL;
104}
105
106void dns_zone_remove_rr(DnsZone *z, DnsResourceRecord *rr) {
107 DnsZoneItem *i;
108
109 assert(z);
110 assert(rr);
111
112 i = dns_zone_get(z, rr);
113 if (i)
114 dns_zone_item_remove_and_free(z, i);
115}
116
117static int dns_zone_init(DnsZone *z) {
118 int r;
119
120 assert(z);
121
122 r = hashmap_ensure_allocated(&z->by_key, dns_resource_key_hash_func, dns_resource_key_compare_func);
123 if (r < 0)
124 return r;
125
126 r = hashmap_ensure_allocated(&z->by_name, dns_name_hash_func, dns_name_compare_func);
127 if (r < 0)
128 return r;
129
130 return 0;
131}
132
133static int dns_zone_link_item(DnsZone *z, DnsZoneItem *i) {
134 DnsZoneItem *first;
135 int r;
136
137 first = hashmap_get(z->by_key, i->rr->key);
138 if (first) {
139 LIST_PREPEND(by_key, first, i);
140 assert_se(hashmap_replace(z->by_key, first->rr->key, first) >= 0);
141 } else {
142 r = hashmap_put(z->by_key, i->rr->key, i);
143 if (r < 0)
144 return r;
145 }
146
147 first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key));
148 if (first) {
149 LIST_PREPEND(by_name, first, i);
150 assert_se(hashmap_replace(z->by_name, DNS_RESOURCE_KEY_NAME(first->rr->key), first) >= 0);
151 } else {
152 r = hashmap_put(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key), i);
153 if (r < 0)
154 return r;
155 }
156
157 return 0;
158}
159
160int dns_zone_put(DnsZone *z, DnsResourceRecord *rr) {
161 _cleanup_(dns_zone_item_freep) DnsZoneItem *i = NULL;
162 DnsZoneItem *existing;
163 int r;
164
165 assert(z);
166 assert(rr);
167
1d3b690f
LP
168 if (rr->key->class == DNS_CLASS_ANY)
169 return -EINVAL;
170 if (rr->key->type == DNS_TYPE_ANY)
171 return -EINVAL;
172
623a4c97
LP
173 existing = dns_zone_get(z, rr);
174 if (existing)
175 return 0;
176
177 r = dns_zone_init(z);
178 if (r < 0)
179 return r;
180
181 i = new0(DnsZoneItem, 1);
182 if (!i)
183 return -ENOMEM;
184
185 i->rr = dns_resource_record_ref(rr);
186
187 r = dns_zone_link_item(z, i);
188 if (r < 0)
189 return r;
190
191 i = NULL;
192 return 0;
193}
194
195int dns_zone_lookup(DnsZone *z, DnsQuestion *q, DnsAnswer **ret) {
196 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
197 int r;
198 unsigned i, n = 0;
199 bool has_other_rrs = false;
200
201 assert(z);
202 assert(q);
203 assert(ret);
204
205 if (q->n_keys <= 0) {
206 *ret = NULL;
207 return 0;
208 }
209
210 for (i = 0; i < q->n_keys; i++) {
211 DnsZoneItem *j;
212
213 j = hashmap_get(z->by_key, q->keys[i]);
214 if (!j) {
215 if (hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i])))
216 has_other_rrs = true;
217
218 continue;
219 }
220
221 LIST_FOREACH(by_name, j, j)
222 n++;
223 }
224
225 if (n <= 0) {
226 *ret = NULL;
227 return has_other_rrs;
228 }
229
230 answer = dns_answer_new(n);
231 if (!answer)
232 return -ENOMEM;
233
234 for (i = 0; i < q->n_keys; i++) {
235 DnsZoneItem *j;
236
237 j = hashmap_get(z->by_key, q->keys[i]);
238 LIST_FOREACH(by_key, j, j) {
239 r = dns_answer_add(answer, j->rr);
240 if (r < 0)
241 return r;
242 }
243 }
244
245 *ret = answer;
246 answer = NULL;
247
248 return 1;
249}