/src/unbound/iterator/iter_priv.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * iterator/iter_priv.c - iterative resolver private address and domain store |
3 | | * |
4 | | * Copyright (c) 2008, NLnet Labs. All rights reserved. |
5 | | * |
6 | | * This software is open source. |
7 | | * |
8 | | * Redistribution and use in source and binary forms, with or without |
9 | | * modification, are permitted provided that the following conditions |
10 | | * are met: |
11 | | * |
12 | | * Redistributions of source code must retain the above copyright notice, |
13 | | * this list of conditions and the following disclaimer. |
14 | | * |
15 | | * Redistributions in binary form must reproduce the above copyright notice, |
16 | | * this list of conditions and the following disclaimer in the documentation |
17 | | * and/or other materials provided with the distribution. |
18 | | * |
19 | | * Neither the name of the NLNET LABS nor the names of its contributors may |
20 | | * be used to endorse or promote products derived from this software without |
21 | | * specific prior written permission. |
22 | | * |
23 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
24 | | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
25 | | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
26 | | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
27 | | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
28 | | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
29 | | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
30 | | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
31 | | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
32 | | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
33 | | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
34 | | */ |
35 | | |
36 | | /** |
37 | | * \file |
38 | | * |
39 | | * This file contains functions to assist the iterator module. |
40 | | * Keep track of the private addresses and lookup fast. |
41 | | */ |
42 | | |
43 | | #include "config.h" |
44 | | #include "iterator/iter_priv.h" |
45 | | #include "util/regional.h" |
46 | | #include "util/log.h" |
47 | | #include "util/config_file.h" |
48 | | #include "util/data/dname.h" |
49 | | #include "util/data/msgparse.h" |
50 | | #include "util/net_help.h" |
51 | | #include "util/storage/dnstree.h" |
52 | | #include "sldns/str2wire.h" |
53 | | #include "sldns/sbuffer.h" |
54 | | |
55 | | struct iter_priv* priv_create(void) |
56 | 0 | { |
57 | 0 | struct iter_priv* priv = (struct iter_priv*)calloc(1, sizeof(*priv)); |
58 | 0 | if(!priv) |
59 | 0 | return NULL; |
60 | 0 | priv->region = regional_create(); |
61 | 0 | if(!priv->region) { |
62 | 0 | priv_delete(priv); |
63 | 0 | return NULL; |
64 | 0 | } |
65 | 0 | addr_tree_init(&priv->a); |
66 | 0 | name_tree_init(&priv->n); |
67 | 0 | return priv; |
68 | 0 | } |
69 | | |
70 | | void priv_delete(struct iter_priv* priv) |
71 | 0 | { |
72 | 0 | if(!priv) return; |
73 | 0 | regional_destroy(priv->region); |
74 | 0 | free(priv); |
75 | 0 | } |
76 | | |
77 | | /** Read private-addr declarations from config */ |
78 | | static int read_addrs(struct iter_priv* priv, struct config_file* cfg) |
79 | 0 | { |
80 | | /* parse addresses, report errors, insert into tree */ |
81 | 0 | struct config_strlist* p; |
82 | 0 | struct addr_tree_node* n; |
83 | 0 | struct sockaddr_storage addr; |
84 | 0 | int net; |
85 | 0 | socklen_t addrlen; |
86 | |
|
87 | 0 | for(p = cfg->private_address; p; p = p->next) { |
88 | 0 | log_assert(p->str); |
89 | 0 | if(!netblockstrtoaddr(p->str, UNBOUND_DNS_PORT, &addr, |
90 | 0 | &addrlen, &net)) { |
91 | 0 | log_err("cannot parse private-address: %s", p->str); |
92 | 0 | return 0; |
93 | 0 | } |
94 | 0 | n = (struct addr_tree_node*)regional_alloc(priv->region, |
95 | 0 | sizeof(*n)); |
96 | 0 | if(!n) { |
97 | 0 | log_err("out of memory"); |
98 | 0 | return 0; |
99 | 0 | } |
100 | 0 | if(!addr_tree_insert(&priv->a, n, &addr, addrlen, net)) { |
101 | 0 | verbose(VERB_QUERY, "ignoring duplicate " |
102 | 0 | "private-address: %s", p->str); |
103 | 0 | } |
104 | 0 | } |
105 | 0 | return 1; |
106 | 0 | } |
107 | | |
108 | | /** Read private-domain declarations from config */ |
109 | | static int read_names(struct iter_priv* priv, struct config_file* cfg) |
110 | 0 | { |
111 | | /* parse names, report errors, insert into tree */ |
112 | 0 | struct config_strlist* p; |
113 | 0 | struct name_tree_node* n; |
114 | 0 | uint8_t* nm, *nmr; |
115 | 0 | size_t nm_len; |
116 | 0 | int nm_labs; |
117 | |
|
118 | 0 | for(p = cfg->private_domain; p; p = p->next) { |
119 | 0 | log_assert(p->str); |
120 | 0 | nm = sldns_str2wire_dname(p->str, &nm_len); |
121 | 0 | if(!nm) { |
122 | 0 | log_err("cannot parse private-domain: %s", p->str); |
123 | 0 | return 0; |
124 | 0 | } |
125 | 0 | nm_labs = dname_count_size_labels(nm, &nm_len); |
126 | 0 | nmr = (uint8_t*)regional_alloc_init(priv->region, nm, nm_len); |
127 | 0 | free(nm); |
128 | 0 | if(!nmr) { |
129 | 0 | log_err("out of memory"); |
130 | 0 | return 0; |
131 | 0 | } |
132 | 0 | n = (struct name_tree_node*)regional_alloc(priv->region, |
133 | 0 | sizeof(*n)); |
134 | 0 | if(!n) { |
135 | 0 | log_err("out of memory"); |
136 | 0 | return 0; |
137 | 0 | } |
138 | 0 | if(!name_tree_insert(&priv->n, n, nmr, nm_len, nm_labs, |
139 | 0 | LDNS_RR_CLASS_IN)) { |
140 | 0 | verbose(VERB_QUERY, "ignoring duplicate " |
141 | 0 | "private-domain: %s", p->str); |
142 | 0 | } |
143 | 0 | } |
144 | 0 | return 1; |
145 | 0 | } |
146 | | |
147 | | int priv_apply_cfg(struct iter_priv* priv, struct config_file* cfg) |
148 | 0 | { |
149 | | /* empty the current contents */ |
150 | 0 | regional_free_all(priv->region); |
151 | 0 | addr_tree_init(&priv->a); |
152 | 0 | name_tree_init(&priv->n); |
153 | | |
154 | | /* read new contents */ |
155 | 0 | if(!read_addrs(priv, cfg)) |
156 | 0 | return 0; |
157 | 0 | if(!read_names(priv, cfg)) |
158 | 0 | return 0; |
159 | | |
160 | | /* prepare for lookups */ |
161 | 0 | addr_tree_init_parents(&priv->a); |
162 | 0 | name_tree_init_parents(&priv->n); |
163 | 0 | return 1; |
164 | 0 | } |
165 | | |
166 | | /** |
167 | | * See if an address is blocked. |
168 | | * @param priv: structure for address storage. |
169 | | * @param addr: address to check |
170 | | * @param addrlen: length of addr. |
171 | | * @return: true if the address must not be queried. false if unlisted. |
172 | | */ |
173 | | static int |
174 | | priv_lookup_addr(struct iter_priv* priv, struct sockaddr_storage* addr, |
175 | | socklen_t addrlen) |
176 | 0 | { |
177 | 0 | return addr_tree_lookup(&priv->a, addr, addrlen) != NULL; |
178 | 0 | } |
179 | | |
180 | | /** |
181 | | * See if a name is whitelisted. |
182 | | * @param priv: structure for address storage. |
183 | | * @param pkt: the packet (for compression ptrs). |
184 | | * @param name: name to check. |
185 | | * @param name_len: uncompressed length of the name to check. |
186 | | * @param dclass: class to check. |
187 | | * @return: true if the name is OK. false if unlisted. |
188 | | */ |
189 | | static int |
190 | | priv_lookup_name(struct iter_priv* priv, sldns_buffer* pkt, |
191 | | uint8_t* name, size_t name_len, uint16_t dclass) |
192 | 0 | { |
193 | 0 | size_t len; |
194 | 0 | uint8_t decomp[256]; |
195 | 0 | int labs; |
196 | 0 | if(name_len >= sizeof(decomp)) |
197 | 0 | return 0; |
198 | 0 | dname_pkt_copy(pkt, decomp, name); |
199 | 0 | labs = dname_count_size_labels(decomp, &len); |
200 | 0 | log_assert(name_len == len); |
201 | 0 | return name_tree_lookup(&priv->n, decomp, len, labs, dclass) != NULL; |
202 | 0 | } |
203 | | |
204 | | size_t priv_get_mem(struct iter_priv* priv) |
205 | 0 | { |
206 | 0 | if(!priv) return 0; |
207 | 0 | return sizeof(*priv) + regional_get_mem(priv->region); |
208 | 0 | } |
209 | | |
210 | | int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt, |
211 | | struct rrset_parse* rrset) |
212 | 9.66k | { |
213 | 9.66k | if(priv->a.count == 0) |
214 | 9.66k | return 0; /* there are no blocked addresses */ |
215 | | |
216 | | /* see if it is a private name, that is allowed to have any */ |
217 | 0 | if(priv_lookup_name(priv, pkt, rrset->dname, rrset->dname_len, |
218 | 0 | ntohs(rrset->rrset_class))) { |
219 | 0 | return 0; |
220 | 0 | } else { |
221 | | /* so its a public name, check the address */ |
222 | 0 | socklen_t len; |
223 | 0 | struct rr_parse* rr, *prev = NULL; |
224 | 0 | if(rrset->type == LDNS_RR_TYPE_A) { |
225 | 0 | struct sockaddr_storage addr; |
226 | 0 | struct sockaddr_in sa; |
227 | |
|
228 | 0 | len = (socklen_t)sizeof(sa); |
229 | 0 | memset(&sa, 0, len); |
230 | 0 | sa.sin_family = AF_INET; |
231 | 0 | sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT); |
232 | 0 | for(rr = rrset->rr_first; rr; rr = rr->next) { |
233 | 0 | if(sldns_read_uint16(rr->ttl_data+4) |
234 | 0 | != INET_SIZE) { |
235 | 0 | prev = rr; |
236 | 0 | continue; |
237 | 0 | } |
238 | 0 | memmove(&sa.sin_addr, rr->ttl_data+4+2, |
239 | 0 | INET_SIZE); |
240 | 0 | memmove(&addr, &sa, len); |
241 | 0 | if(priv_lookup_addr(priv, &addr, len)) { |
242 | 0 | if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, len)) |
243 | 0 | return 1; |
244 | 0 | continue; |
245 | 0 | } |
246 | 0 | prev = rr; |
247 | 0 | } |
248 | 0 | } else if(rrset->type == LDNS_RR_TYPE_AAAA) { |
249 | 0 | struct sockaddr_storage addr; |
250 | 0 | struct sockaddr_in6 sa; |
251 | 0 | len = (socklen_t)sizeof(sa); |
252 | 0 | memset(&sa, 0, len); |
253 | 0 | sa.sin6_family = AF_INET6; |
254 | 0 | sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT); |
255 | 0 | for(rr = rrset->rr_first; rr; rr = rr->next) { |
256 | 0 | if(sldns_read_uint16(rr->ttl_data+4) |
257 | 0 | != INET6_SIZE) { |
258 | 0 | prev = rr; |
259 | 0 | continue; |
260 | 0 | } |
261 | 0 | memmove(&sa.sin6_addr, rr->ttl_data+4+2, |
262 | 0 | INET6_SIZE); |
263 | 0 | memmove(&addr, &sa, len); |
264 | 0 | if(priv_lookup_addr(priv, &addr, len)) { |
265 | 0 | if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, len)) |
266 | 0 | return 1; |
267 | 0 | continue; |
268 | 0 | } |
269 | 0 | prev = rr; |
270 | 0 | } |
271 | 0 | } |
272 | 0 | } |
273 | 0 | return 0; |
274 | 0 | } |