/src/unbound/util/module.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * util/module.c - module interface |
3 | | * |
4 | | * Copyright (c) 2007, 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 | | * \file |
37 | | * Implementation of module.h. |
38 | | */ |
39 | | |
40 | | #include "config.h" |
41 | | #include "util/module.h" |
42 | | #include "sldns/wire2str.h" |
43 | | #include "util/config_file.h" |
44 | | #include "util/regional.h" |
45 | | #include "util/data/dname.h" |
46 | | #include "util/net_help.h" |
47 | | |
48 | | const char* |
49 | | strextstate(enum module_ext_state s) |
50 | 0 | { |
51 | 0 | switch(s) { |
52 | 0 | case module_state_initial: return "module_state_initial"; |
53 | 0 | case module_wait_reply: return "module_wait_reply"; |
54 | 0 | case module_wait_module: return "module_wait_module"; |
55 | 0 | case module_restart_next: return "module_restart_next"; |
56 | 0 | case module_wait_subquery: return "module_wait_subquery"; |
57 | 0 | case module_error: return "module_error"; |
58 | 0 | case module_finished: return "module_finished"; |
59 | 0 | } |
60 | 0 | return "bad_extstate_value"; |
61 | 0 | } |
62 | | |
63 | | const char* |
64 | | strmodulevent(enum module_ev e) |
65 | 0 | { |
66 | 0 | switch(e) { |
67 | 0 | case module_event_new: return "module_event_new"; |
68 | 0 | case module_event_pass: return "module_event_pass"; |
69 | 0 | case module_event_reply: return "module_event_reply"; |
70 | 0 | case module_event_noreply: return "module_event_noreply"; |
71 | 0 | case module_event_capsfail: return "module_event_capsfail"; |
72 | 0 | case module_event_moddone: return "module_event_moddone"; |
73 | 0 | case module_event_error: return "module_event_error"; |
74 | 0 | } |
75 | 0 | return "bad_event_value"; |
76 | 0 | } |
77 | | |
78 | | void errinf(struct module_qstate* qstate, const char* str) |
79 | 0 | { |
80 | 0 | errinf_ede(qstate, str, LDNS_EDE_NONE); |
81 | 0 | } |
82 | | |
83 | | void errinf_ede(struct module_qstate* qstate, |
84 | | const char* str, sldns_ede_code reason_bogus) |
85 | 0 | { |
86 | 0 | struct errinf_strlist* p; |
87 | 0 | if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !str) |
88 | 0 | return; |
89 | 0 | p = (struct errinf_strlist*)regional_alloc(qstate->region, sizeof(*p)); |
90 | 0 | if(!p) { |
91 | 0 | log_err("malloc failure in validator-error-info string"); |
92 | 0 | return; |
93 | 0 | } |
94 | 0 | p->next = NULL; |
95 | 0 | p->str = regional_strdup(qstate->region, str); |
96 | 0 | p->reason_bogus = reason_bogus; |
97 | 0 | if(!p->str) { |
98 | 0 | log_err("malloc failure in validator-error-info string"); |
99 | 0 | return; |
100 | 0 | } |
101 | | /* add at end */ |
102 | 0 | if(qstate->errinf) { |
103 | 0 | struct errinf_strlist* q = qstate->errinf; |
104 | 0 | while(q->next) |
105 | 0 | q = q->next; |
106 | 0 | q->next = p; |
107 | 0 | } else qstate->errinf = p; |
108 | 0 | } |
109 | | |
110 | | void errinf_origin(struct module_qstate* qstate, struct sock_list *origin) |
111 | 0 | { |
112 | 0 | struct sock_list* p; |
113 | 0 | if(qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) |
114 | 0 | return; |
115 | 0 | for(p=origin; p; p=p->next) { |
116 | 0 | char buf[256]; |
117 | 0 | if(p == origin) |
118 | 0 | snprintf(buf, sizeof(buf), "from "); |
119 | 0 | else snprintf(buf, sizeof(buf), "and "); |
120 | 0 | if(p->len == 0) |
121 | 0 | snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), |
122 | 0 | "cache"); |
123 | 0 | else |
124 | 0 | addr_to_str(&p->addr, p->len, buf+strlen(buf), |
125 | 0 | sizeof(buf)-strlen(buf)); |
126 | 0 | errinf(qstate, buf); |
127 | 0 | } |
128 | 0 | } |
129 | | |
130 | | char* errinf_to_str_bogus(struct module_qstate* qstate) |
131 | 0 | { |
132 | 0 | char buf[20480]; |
133 | 0 | char* p = buf; |
134 | 0 | size_t left = sizeof(buf); |
135 | 0 | struct errinf_strlist* s; |
136 | 0 | char dname[LDNS_MAX_DOMAINLEN+1]; |
137 | 0 | char t[16], c[16]; |
138 | 0 | sldns_wire2str_type_buf(qstate->qinfo.qtype, t, sizeof(t)); |
139 | 0 | sldns_wire2str_class_buf(qstate->qinfo.qclass, c, sizeof(c)); |
140 | 0 | dname_str(qstate->qinfo.qname, dname); |
141 | 0 | snprintf(p, left, "validation failure <%s %s %s>:", dname, t, c); |
142 | 0 | left -= strlen(p); p += strlen(p); |
143 | 0 | if(!qstate->errinf) |
144 | 0 | snprintf(p, left, " misc failure"); |
145 | 0 | else for(s=qstate->errinf; s; s=s->next) { |
146 | 0 | snprintf(p, left, " %s", s->str); |
147 | 0 | left -= strlen(p); p += strlen(p); |
148 | 0 | } |
149 | 0 | p = strdup(buf); |
150 | 0 | if(!p) |
151 | 0 | log_err("malloc failure in errinf_to_str"); |
152 | 0 | return p; |
153 | 0 | } |
154 | | |
155 | | sldns_ede_code errinf_to_reason_bogus(struct module_qstate* qstate) |
156 | 0 | { |
157 | 0 | struct errinf_strlist* s; |
158 | 0 | for(s=qstate->errinf; s; s=s->next) { |
159 | 0 | if (s->reason_bogus != LDNS_EDE_NONE) { |
160 | 0 | return s->reason_bogus; |
161 | 0 | } |
162 | 0 | } |
163 | 0 | return LDNS_EDE_NONE; |
164 | 0 | } |
165 | | |
166 | | char* errinf_to_str_servfail(struct module_qstate* qstate) |
167 | 0 | { |
168 | 0 | char buf[20480]; |
169 | 0 | char* p = buf; |
170 | 0 | size_t left = sizeof(buf); |
171 | 0 | struct errinf_strlist* s; |
172 | 0 | char dname[LDNS_MAX_DOMAINLEN+1]; |
173 | 0 | char t[16], c[16]; |
174 | 0 | sldns_wire2str_type_buf(qstate->qinfo.qtype, t, sizeof(t)); |
175 | 0 | sldns_wire2str_class_buf(qstate->qinfo.qclass, c, sizeof(c)); |
176 | 0 | dname_str(qstate->qinfo.qname, dname); |
177 | 0 | snprintf(p, left, "SERVFAIL <%s %s %s>:", dname, t, c); |
178 | 0 | left -= strlen(p); p += strlen(p); |
179 | 0 | if(!qstate->errinf) |
180 | 0 | snprintf(p, left, " misc failure"); |
181 | 0 | else for(s=qstate->errinf; s; s=s->next) { |
182 | 0 | snprintf(p, left, " %s", s->str); |
183 | 0 | left -= strlen(p); p += strlen(p); |
184 | 0 | } |
185 | 0 | p = strdup(buf); |
186 | 0 | if(!p) |
187 | 0 | log_err("malloc failure in errinf_to_str"); |
188 | 0 | return p; |
189 | 0 | } |
190 | | |
191 | | void errinf_rrset(struct module_qstate* qstate, struct ub_packed_rrset_key *rr) |
192 | 0 | { |
193 | 0 | char buf[1024]; |
194 | 0 | char dname[LDNS_MAX_DOMAINLEN+1]; |
195 | 0 | char t[16], c[16]; |
196 | 0 | if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !rr) |
197 | 0 | return; |
198 | 0 | sldns_wire2str_type_buf(ntohs(rr->rk.type), t, sizeof(t)); |
199 | 0 | sldns_wire2str_class_buf(ntohs(rr->rk.rrset_class), c, sizeof(c)); |
200 | 0 | dname_str(rr->rk.dname, dname); |
201 | 0 | snprintf(buf, sizeof(buf), "for <%s %s %s>", dname, t, c); |
202 | 0 | errinf(qstate, buf); |
203 | 0 | } |
204 | | |
205 | | void errinf_dname(struct module_qstate* qstate, const char* str, uint8_t* dname) |
206 | 0 | { |
207 | 0 | char b[1024]; |
208 | 0 | char buf[LDNS_MAX_DOMAINLEN+1]; |
209 | 0 | if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !str || !dname) |
210 | 0 | return; |
211 | 0 | dname_str(dname, buf); |
212 | 0 | snprintf(b, sizeof(b), "%s %s", str, buf); |
213 | 0 | errinf(qstate, b); |
214 | 0 | } |
215 | | |
216 | | int |
217 | | edns_known_options_init(struct module_env* env) |
218 | 0 | { |
219 | 0 | env->edns_known_options_num = 0; |
220 | 0 | env->edns_known_options = (struct edns_known_option*)calloc( |
221 | 0 | MAX_KNOWN_EDNS_OPTS, sizeof(struct edns_known_option)); |
222 | 0 | if(!env->edns_known_options) return 0; |
223 | 0 | return 1; |
224 | 0 | } |
225 | | |
226 | | void |
227 | | edns_known_options_delete(struct module_env* env) |
228 | 0 | { |
229 | 0 | free(env->edns_known_options); |
230 | 0 | env->edns_known_options = NULL; |
231 | 0 | env->edns_known_options_num = 0; |
232 | 0 | } |
233 | | |
234 | | int |
235 | | edns_register_option(uint16_t opt_code, int bypass_cache_stage, |
236 | | int no_aggregation, struct module_env* env) |
237 | 0 | { |
238 | 0 | size_t i; |
239 | 0 | if(env->worker) { |
240 | 0 | log_err("invalid edns registration: " |
241 | 0 | "trying to register option after module init phase"); |
242 | 0 | return 0; |
243 | 0 | } |
244 | | |
245 | | /** |
246 | | * Checking if we are full first is faster but it does not provide |
247 | | * the option to change the flags when the array is full. |
248 | | * It only impacts unbound initialization, leave it for now. |
249 | | */ |
250 | | /* Check if the option is already registered. */ |
251 | 0 | for(i=0; i<env->edns_known_options_num; i++) |
252 | 0 | if(env->edns_known_options[i].opt_code == opt_code) |
253 | 0 | break; |
254 | | /* If it is not yet registered check if we have space to add a new one. */ |
255 | 0 | if(i == env->edns_known_options_num) { |
256 | 0 | if(env->edns_known_options_num >= MAX_KNOWN_EDNS_OPTS) { |
257 | 0 | log_err("invalid edns registration: maximum options reached"); |
258 | 0 | return 0; |
259 | 0 | } |
260 | 0 | env->edns_known_options_num++; |
261 | 0 | } |
262 | 0 | env->edns_known_options[i].opt_code = opt_code; |
263 | 0 | env->edns_known_options[i].bypass_cache_stage = bypass_cache_stage; |
264 | 0 | env->edns_known_options[i].no_aggregation = no_aggregation; |
265 | 0 | return 1; |
266 | 0 | } |
267 | | |
268 | | int |
269 | | inplace_cb_register(void* cb, enum inplace_cb_list_type type, void* cbarg, |
270 | | struct module_env* env, int id) |
271 | 0 | { |
272 | 0 | struct inplace_cb* callback; |
273 | 0 | struct inplace_cb** prevp; |
274 | 0 | if(env->worker) { |
275 | 0 | log_err("invalid edns callback registration: " |
276 | 0 | "trying to register callback after module init phase"); |
277 | 0 | return 0; |
278 | 0 | } |
279 | | |
280 | 0 | callback = (struct inplace_cb*)calloc(1, sizeof(*callback)); |
281 | 0 | if(callback == NULL) { |
282 | 0 | log_err("out of memory during edns callback registration."); |
283 | 0 | return 0; |
284 | 0 | } |
285 | 0 | callback->id = id; |
286 | 0 | callback->next = NULL; |
287 | 0 | callback->cb = cb; |
288 | 0 | callback->cb_arg = cbarg; |
289 | | |
290 | 0 | prevp = (struct inplace_cb**) &env->inplace_cb_lists[type]; |
291 | | /* append at end of list */ |
292 | 0 | while(*prevp != NULL) |
293 | 0 | prevp = &((*prevp)->next); |
294 | 0 | *prevp = callback; |
295 | 0 | return 1; |
296 | 0 | } |
297 | | |
298 | | void |
299 | | inplace_cb_delete(struct module_env* env, enum inplace_cb_list_type type, |
300 | | int id) |
301 | 0 | { |
302 | 0 | struct inplace_cb* temp = env->inplace_cb_lists[type]; |
303 | 0 | struct inplace_cb* prev = NULL; |
304 | |
|
305 | 0 | while(temp) { |
306 | 0 | if(temp->id == id) { |
307 | 0 | if(!prev) { |
308 | 0 | env->inplace_cb_lists[type] = temp->next; |
309 | 0 | free(temp); |
310 | 0 | temp = env->inplace_cb_lists[type]; |
311 | 0 | } |
312 | 0 | else { |
313 | 0 | prev->next = temp->next; |
314 | 0 | free(temp); |
315 | 0 | temp = prev->next; |
316 | 0 | } |
317 | 0 | } |
318 | 0 | else { |
319 | 0 | prev = temp; |
320 | 0 | temp = temp->next; |
321 | 0 | } |
322 | 0 | } |
323 | 0 | } |
324 | | |
325 | | struct edns_known_option* |
326 | | edns_option_is_known(uint16_t opt_code, struct module_env* env) |
327 | 0 | { |
328 | 0 | size_t i; |
329 | 0 | for(i=0; i<env->edns_known_options_num; i++) |
330 | 0 | if(env->edns_known_options[i].opt_code == opt_code) |
331 | 0 | return env->edns_known_options + i; |
332 | 0 | return NULL; |
333 | 0 | } |
334 | | |
335 | | int |
336 | | edns_bypass_cache_stage(struct edns_option* list, struct module_env* env) |
337 | 0 | { |
338 | 0 | size_t i; |
339 | 0 | for(; list; list=list->next) |
340 | 0 | for(i=0; i<env->edns_known_options_num; i++) |
341 | 0 | if(env->edns_known_options[i].opt_code == list->opt_code && |
342 | 0 | env->edns_known_options[i].bypass_cache_stage == 1) |
343 | 0 | return 1; |
344 | 0 | return 0; |
345 | 0 | } |
346 | | |
347 | | int |
348 | | unique_mesh_state(struct edns_option* list, struct module_env* env) |
349 | 0 | { |
350 | 0 | size_t i; |
351 | 0 | if(env->unique_mesh) |
352 | 0 | return 1; |
353 | 0 | for(; list; list=list->next) |
354 | 0 | for(i=0; i<env->edns_known_options_num; i++) |
355 | 0 | if(env->edns_known_options[i].opt_code == list->opt_code && |
356 | 0 | env->edns_known_options[i].no_aggregation == 1) |
357 | 0 | return 1; |
358 | 0 | return 0; |
359 | 0 | } |
360 | | |
361 | | void |
362 | | log_edns_known_options(enum verbosity_value level, struct module_env* env) |
363 | 0 | { |
364 | 0 | size_t i; |
365 | 0 | char str[32], *s; |
366 | 0 | size_t slen; |
367 | 0 | if(env->edns_known_options_num > 0 && verbosity >= level) { |
368 | 0 | verbose(level, "EDNS known options:"); |
369 | 0 | verbose(level, " Code: Bypass_cache_stage: Aggregate_mesh:"); |
370 | 0 | for(i=0; i<env->edns_known_options_num; i++) { |
371 | 0 | s = str; |
372 | 0 | slen = sizeof(str); |
373 | 0 | (void)sldns_wire2str_edns_option_code_print(&s, &slen, |
374 | 0 | env->edns_known_options[i].opt_code); |
375 | 0 | verbose(level, " %-8.8s %-19s %-15s", str, |
376 | 0 | env->edns_known_options[i].bypass_cache_stage?"YES":"NO", |
377 | 0 | env->edns_known_options[i].no_aggregation?"NO":"YES"); |
378 | 0 | } |
379 | 0 | } |
380 | 0 | } |
381 | | |
382 | | void |
383 | | copy_state_to_super(struct module_qstate* qstate, int ATTR_UNUSED(id), |
384 | | struct module_qstate* super) |
385 | 0 | { |
386 | | /* Overwrite super's was_ratelimited only when it was not set */ |
387 | 0 | if(!super->was_ratelimited) { |
388 | 0 | super->was_ratelimited = qstate->was_ratelimited; |
389 | 0 | } |
390 | 0 | } |