/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 | 488 | { |
86 | 488 | struct errinf_strlist* p; |
87 | 488 | if(!str || (qstate->env->cfg->val_log_level < 2 && |
88 | 488 | !qstate->env->cfg->log_servfail)) { |
89 | 488 | return; |
90 | 488 | } |
91 | 0 | p = (struct errinf_strlist*)regional_alloc(qstate->region, sizeof(*p)); |
92 | 0 | if(!p) { |
93 | 0 | log_err("malloc failure in validator-error-info string"); |
94 | 0 | return; |
95 | 0 | } |
96 | 0 | p->next = NULL; |
97 | 0 | p->str = regional_strdup(qstate->region, str); |
98 | 0 | p->reason_bogus = reason_bogus; |
99 | 0 | if(!p->str) { |
100 | 0 | log_err("malloc failure in validator-error-info string"); |
101 | 0 | return; |
102 | 0 | } |
103 | | /* add at end */ |
104 | 0 | if(qstate->errinf) { |
105 | 0 | struct errinf_strlist* q = qstate->errinf; |
106 | 0 | while(q->next) |
107 | 0 | q = q->next; |
108 | 0 | q->next = p; |
109 | 0 | } else qstate->errinf = p; |
110 | 0 | } |
111 | | |
112 | | void errinf_origin(struct module_qstate* qstate, struct sock_list *origin) |
113 | 0 | { |
114 | 0 | struct sock_list* p; |
115 | 0 | if(qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) |
116 | 0 | return; |
117 | 0 | for(p=origin; p; p=p->next) { |
118 | 0 | char buf[256]; |
119 | 0 | if(p == origin) |
120 | 0 | snprintf(buf, sizeof(buf), "from "); |
121 | 0 | else snprintf(buf, sizeof(buf), "and "); |
122 | 0 | if(p->len == 0) |
123 | 0 | snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), |
124 | 0 | "cache"); |
125 | 0 | else |
126 | 0 | addr_to_str(&p->addr, p->len, buf+strlen(buf), |
127 | 0 | sizeof(buf)-strlen(buf)); |
128 | 0 | errinf(qstate, buf); |
129 | 0 | } |
130 | 0 | } |
131 | | |
132 | | char* errinf_to_str_bogus(struct module_qstate* qstate, struct regional* region) |
133 | 0 | { |
134 | 0 | char buf[20480]; |
135 | 0 | char* p = buf; |
136 | 0 | size_t left = sizeof(buf); |
137 | 0 | struct errinf_strlist* s; |
138 | 0 | char dname[LDNS_MAX_DOMAINLEN]; |
139 | 0 | char t[16], c[16]; |
140 | 0 | sldns_wire2str_type_buf(qstate->qinfo.qtype, t, sizeof(t)); |
141 | 0 | sldns_wire2str_class_buf(qstate->qinfo.qclass, c, sizeof(c)); |
142 | 0 | dname_str(qstate->qinfo.qname, dname); |
143 | 0 | snprintf(p, left, "validation failure <%s %s %s>:", dname, t, c); |
144 | 0 | left -= strlen(p); p += strlen(p); |
145 | 0 | if(!qstate->errinf) |
146 | 0 | snprintf(p, left, " misc failure"); |
147 | 0 | else for(s=qstate->errinf; s; s=s->next) { |
148 | 0 | snprintf(p, left, " %s", s->str); |
149 | 0 | left -= strlen(p); p += strlen(p); |
150 | 0 | } |
151 | 0 | if(region) |
152 | 0 | p = regional_strdup(region, buf); |
153 | 0 | else |
154 | 0 | p = strdup(buf); |
155 | 0 | if(!p) |
156 | 0 | log_err("malloc failure in errinf_to_str"); |
157 | 0 | return p; |
158 | 0 | } |
159 | | |
160 | | /* Try to find the latest (most specific) dnssec failure */ |
161 | | sldns_ede_code errinf_to_reason_bogus(struct module_qstate* qstate) |
162 | 0 | { |
163 | 0 | struct errinf_strlist* s; |
164 | 0 | sldns_ede_code ede = LDNS_EDE_NONE; |
165 | 0 | for(s=qstate->errinf; s; s=s->next) { |
166 | 0 | if(s->reason_bogus == LDNS_EDE_NONE) continue; |
167 | 0 | if(ede != LDNS_EDE_NONE |
168 | 0 | && ede != LDNS_EDE_DNSSEC_BOGUS |
169 | 0 | && s->reason_bogus == LDNS_EDE_DNSSEC_BOGUS) continue; |
170 | 0 | ede = s->reason_bogus; |
171 | 0 | } |
172 | 0 | return ede; |
173 | 0 | } |
174 | | |
175 | | char* errinf_to_str_servfail(struct module_qstate* qstate) |
176 | 0 | { |
177 | 0 | char buf[20480]; |
178 | 0 | char* p = buf; |
179 | 0 | size_t left = sizeof(buf); |
180 | 0 | struct errinf_strlist* s; |
181 | 0 | char dname[LDNS_MAX_DOMAINLEN]; |
182 | 0 | char t[16], c[16]; |
183 | 0 | sldns_wire2str_type_buf(qstate->qinfo.qtype, t, sizeof(t)); |
184 | 0 | sldns_wire2str_class_buf(qstate->qinfo.qclass, c, sizeof(c)); |
185 | 0 | dname_str(qstate->qinfo.qname, dname); |
186 | 0 | snprintf(p, left, "SERVFAIL <%s %s %s>:", dname, t, c); |
187 | 0 | left -= strlen(p); p += strlen(p); |
188 | 0 | if(!qstate->errinf) |
189 | 0 | snprintf(p, left, " misc failure"); |
190 | 0 | else for(s=qstate->errinf; s; s=s->next) { |
191 | 0 | snprintf(p, left, " %s", s->str); |
192 | 0 | left -= strlen(p); p += strlen(p); |
193 | 0 | } |
194 | 0 | p = regional_strdup(qstate->region, buf); |
195 | 0 | if(!p) |
196 | 0 | log_err("malloc failure in errinf_to_str"); |
197 | 0 | return p; |
198 | 0 | } |
199 | | |
200 | | char* errinf_to_str_misc(struct module_qstate* qstate) |
201 | 0 | { |
202 | 0 | char buf[20480]; |
203 | 0 | char* p = buf; |
204 | 0 | size_t left = sizeof(buf); |
205 | 0 | struct errinf_strlist* s; |
206 | 0 | if(!qstate->errinf) |
207 | 0 | snprintf(p, left, "misc failure"); |
208 | 0 | else for(s=qstate->errinf; s; s=s->next) { |
209 | 0 | snprintf(p, left, "%s%s", (s==qstate->errinf?"":" "), s->str); |
210 | 0 | left -= strlen(p); p += strlen(p); |
211 | 0 | } |
212 | 0 | p = regional_strdup(qstate->region, buf); |
213 | 0 | if(!p) |
214 | 0 | log_err("malloc failure in errinf_to_str"); |
215 | 0 | return p; |
216 | 0 | } |
217 | | |
218 | | void errinf_rrset(struct module_qstate* qstate, struct ub_packed_rrset_key *rr) |
219 | 0 | { |
220 | 0 | char buf[1024]; |
221 | 0 | char dname[LDNS_MAX_DOMAINLEN]; |
222 | 0 | char t[16], c[16]; |
223 | 0 | if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !rr) |
224 | 0 | return; |
225 | 0 | sldns_wire2str_type_buf(ntohs(rr->rk.type), t, sizeof(t)); |
226 | 0 | sldns_wire2str_class_buf(ntohs(rr->rk.rrset_class), c, sizeof(c)); |
227 | 0 | dname_str(rr->rk.dname, dname); |
228 | 0 | snprintf(buf, sizeof(buf), "for <%s %s %s>", dname, t, c); |
229 | 0 | errinf(qstate, buf); |
230 | 0 | } |
231 | | |
232 | | void errinf_dname(struct module_qstate* qstate, const char* str, uint8_t* dname) |
233 | 0 | { |
234 | 0 | char b[1024]; |
235 | 0 | char buf[LDNS_MAX_DOMAINLEN]; |
236 | 0 | if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !str || !dname) |
237 | 0 | return; |
238 | 0 | dname_str(dname, buf); |
239 | 0 | snprintf(b, sizeof(b), "%s %s", str, buf); |
240 | 0 | errinf(qstate, b); |
241 | 0 | } |
242 | | |
243 | | int |
244 | | edns_known_options_init(struct module_env* env) |
245 | 0 | { |
246 | 0 | env->edns_known_options_num = 0; |
247 | 0 | env->edns_known_options = (struct edns_known_option*)calloc( |
248 | 0 | MAX_KNOWN_EDNS_OPTS, sizeof(struct edns_known_option)); |
249 | 0 | if(!env->edns_known_options) return 0; |
250 | 0 | return 1; |
251 | 0 | } |
252 | | |
253 | | void |
254 | | edns_known_options_delete(struct module_env* env) |
255 | 0 | { |
256 | 0 | free(env->edns_known_options); |
257 | 0 | env->edns_known_options = NULL; |
258 | 0 | env->edns_known_options_num = 0; |
259 | 0 | } |
260 | | |
261 | | int |
262 | | edns_register_option(uint16_t opt_code, int bypass_cache_stage, |
263 | | int no_aggregation, struct module_env* env) |
264 | 0 | { |
265 | 0 | size_t i; |
266 | 0 | if(env->worker) { |
267 | 0 | log_err("invalid edns registration: " |
268 | 0 | "trying to register option after module init phase"); |
269 | 0 | return 0; |
270 | 0 | } |
271 | | |
272 | | /** |
273 | | * Checking if we are full first is faster but it does not provide |
274 | | * the option to change the flags when the array is full. |
275 | | * It only impacts unbound initialization, leave it for now. |
276 | | */ |
277 | | /* Check if the option is already registered. */ |
278 | 0 | for(i=0; i<env->edns_known_options_num; i++) |
279 | 0 | if(env->edns_known_options[i].opt_code == opt_code) |
280 | 0 | break; |
281 | | /* If it is not yet registered check if we have space to add a new one. */ |
282 | 0 | if(i == env->edns_known_options_num) { |
283 | 0 | if(env->edns_known_options_num >= MAX_KNOWN_EDNS_OPTS) { |
284 | 0 | log_err("invalid edns registration: maximum options reached"); |
285 | 0 | return 0; |
286 | 0 | } |
287 | 0 | env->edns_known_options_num++; |
288 | 0 | } |
289 | 0 | env->edns_known_options[i].opt_code = opt_code; |
290 | 0 | env->edns_known_options[i].bypass_cache_stage = bypass_cache_stage; |
291 | 0 | env->edns_known_options[i].no_aggregation = no_aggregation; |
292 | 0 | return 1; |
293 | 0 | } |
294 | | |
295 | | int |
296 | | inplace_cb_register(void* cb, enum inplace_cb_list_type type, void* cbarg, |
297 | | struct module_env* env, int id) |
298 | 0 | { |
299 | 0 | struct inplace_cb* callback; |
300 | 0 | struct inplace_cb** prevp; |
301 | 0 | if(env->worker) { |
302 | 0 | log_err("invalid edns callback registration: " |
303 | 0 | "trying to register callback after module init phase"); |
304 | 0 | return 0; |
305 | 0 | } |
306 | | |
307 | 0 | callback = (struct inplace_cb*)calloc(1, sizeof(*callback)); |
308 | 0 | if(callback == NULL) { |
309 | 0 | log_err("out of memory during edns callback registration."); |
310 | 0 | return 0; |
311 | 0 | } |
312 | 0 | callback->id = id; |
313 | 0 | callback->next = NULL; |
314 | 0 | callback->cb = cb; |
315 | 0 | callback->cb_arg = cbarg; |
316 | | |
317 | 0 | prevp = (struct inplace_cb**) &env->inplace_cb_lists[type]; |
318 | | /* append at end of list */ |
319 | 0 | while(*prevp != NULL) |
320 | 0 | prevp = &((*prevp)->next); |
321 | 0 | *prevp = callback; |
322 | 0 | return 1; |
323 | 0 | } |
324 | | |
325 | | void |
326 | | inplace_cb_delete(struct module_env* env, enum inplace_cb_list_type type, |
327 | | int id) |
328 | 0 | { |
329 | 0 | struct inplace_cb* temp = env->inplace_cb_lists[type]; |
330 | 0 | struct inplace_cb* prev = NULL; |
331 | |
|
332 | 0 | while(temp) { |
333 | 0 | if(temp->id == id) { |
334 | 0 | if(!prev) { |
335 | 0 | env->inplace_cb_lists[type] = temp->next; |
336 | 0 | free(temp); |
337 | 0 | temp = env->inplace_cb_lists[type]; |
338 | 0 | } |
339 | 0 | else { |
340 | 0 | prev->next = temp->next; |
341 | 0 | free(temp); |
342 | 0 | temp = prev->next; |
343 | 0 | } |
344 | 0 | } |
345 | 0 | else { |
346 | 0 | prev = temp; |
347 | 0 | temp = temp->next; |
348 | 0 | } |
349 | 0 | } |
350 | 0 | } |
351 | | |
352 | | struct edns_known_option* |
353 | | edns_option_is_known(uint16_t opt_code, struct module_env* env) |
354 | 0 | { |
355 | 0 | size_t i; |
356 | 0 | for(i=0; i<env->edns_known_options_num; i++) |
357 | 0 | if(env->edns_known_options[i].opt_code == opt_code) |
358 | 0 | return env->edns_known_options + i; |
359 | 0 | return NULL; |
360 | 0 | } |
361 | | |
362 | | int |
363 | | edns_bypass_cache_stage(struct edns_option* list, struct module_env* env) |
364 | 0 | { |
365 | 0 | size_t i; |
366 | 0 | for(; list; list=list->next) |
367 | 0 | for(i=0; i<env->edns_known_options_num; i++) |
368 | 0 | if(env->edns_known_options[i].opt_code == list->opt_code && |
369 | 0 | env->edns_known_options[i].bypass_cache_stage == 1) |
370 | 0 | return 1; |
371 | 0 | return 0; |
372 | 0 | } |
373 | | |
374 | | int |
375 | | unique_mesh_state(struct edns_option* list, struct module_env* env) |
376 | 0 | { |
377 | 0 | size_t i; |
378 | 0 | if(env->unique_mesh) |
379 | 0 | return 1; |
380 | 0 | for(; list; list=list->next) |
381 | 0 | for(i=0; i<env->edns_known_options_num; i++) |
382 | 0 | if(env->edns_known_options[i].opt_code == list->opt_code && |
383 | 0 | env->edns_known_options[i].no_aggregation == 1) |
384 | 0 | return 1; |
385 | 0 | return 0; |
386 | 0 | } |
387 | | |
388 | | void |
389 | | log_edns_known_options(enum verbosity_value level, struct module_env* env) |
390 | 0 | { |
391 | 0 | size_t i; |
392 | 0 | char str[32], *s; |
393 | 0 | size_t slen; |
394 | 0 | if(env->edns_known_options_num > 0 && verbosity >= level) { |
395 | 0 | verbose(level, "EDNS known options:"); |
396 | 0 | verbose(level, " Code: Bypass_cache_stage: Aggregate_mesh:"); |
397 | 0 | for(i=0; i<env->edns_known_options_num; i++) { |
398 | 0 | s = str; |
399 | 0 | slen = sizeof(str); |
400 | 0 | (void)sldns_wire2str_edns_option_code_print(&s, &slen, |
401 | 0 | env->edns_known_options[i].opt_code); |
402 | 0 | verbose(level, " %-8.8s %-19s %-15s", str, |
403 | 0 | env->edns_known_options[i].bypass_cache_stage?"YES":"NO", |
404 | 0 | env->edns_known_options[i].no_aggregation?"NO":"YES"); |
405 | 0 | } |
406 | 0 | } |
407 | 0 | } |
408 | | |
409 | | void |
410 | | copy_state_to_super(struct module_qstate* qstate, int ATTR_UNUSED(id), |
411 | | struct module_qstate* super) |
412 | 0 | { |
413 | | /* Overwrite super's was_ratelimited only when it was not set */ |
414 | 0 | if(!super->was_ratelimited) { |
415 | 0 | super->was_ratelimited = qstate->was_ratelimited; |
416 | 0 | } |
417 | 0 | } |