]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/unbound/util/module.c
Upgrade Unbound to 1.6.1. More to follow.
[FreeBSD/FreeBSD.git] / contrib / unbound / util / module.c
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
44 const char* 
45 strextstate(enum module_ext_state s)
46 {
47         switch(s) {
48         case module_state_initial: return "module_state_initial";
49         case module_wait_reply: return "module_wait_reply";
50         case module_wait_module: return "module_wait_module";
51         case module_restart_next: return "module_restart_next";
52         case module_wait_subquery: return "module_wait_subquery";
53         case module_error: return "module_error";
54         case module_finished: return "module_finished";
55         }
56         return "bad_extstate_value";
57 }
58
59 const char* 
60 strmodulevent(enum module_ev e)
61 {
62         switch(e) {
63         case module_event_new: return "module_event_new";
64         case module_event_pass: return "module_event_pass";
65         case module_event_reply: return "module_event_reply";
66         case module_event_noreply: return "module_event_noreply";
67         case module_event_capsfail: return "module_event_capsfail";
68         case module_event_moddone: return "module_event_moddone";
69         case module_event_error: return "module_event_error";
70         }
71         return "bad_event_value";
72 }
73
74 int
75 edns_known_options_init(struct module_env* env)
76 {
77         env->edns_known_options_num = 0;
78         env->edns_known_options = (struct edns_known_option*)calloc(
79                 MAX_KNOWN_EDNS_OPTS, sizeof(struct edns_known_option));
80         if(!env->edns_known_options) return 0;
81         return 1;
82 }
83
84 void
85 edns_known_options_delete(struct module_env* env)
86 {
87         free(env->edns_known_options);
88         env->edns_known_options = NULL;
89         env->edns_known_options_num = 0;
90 }
91
92 int
93 edns_register_option(uint16_t opt_code, int bypass_cache_stage,
94         int no_aggregation, struct module_env* env)
95 {
96         size_t i;
97         if(env->worker) {
98                 log_err("invalid edns registration: "
99                         "trying to register option after module init phase");
100                 return 0;
101         }
102
103         /**
104          * Checking if we are full first is faster but it does not provide
105          * the option to change the flags when the array is full.
106          * It only impacts unbound initialization, leave it for now.
107          */
108         /* Check if the option is already registered. */
109         for(i=0; i<env->edns_known_options_num; i++)
110                 if(env->edns_known_options[i].opt_code == opt_code)
111                         break;
112         /* If it is not yet registered check if we have space to add a new one. */
113         if(i == env->edns_known_options_num) {
114                 if(env->edns_known_options_num >= MAX_KNOWN_EDNS_OPTS) {
115                         log_err("invalid edns registration: maximum options reached");
116                         return 0;
117                 }
118                 env->edns_known_options_num++;
119         }
120         env->edns_known_options[i].opt_code = opt_code;
121         env->edns_known_options[i].bypass_cache_stage = bypass_cache_stage;
122         env->edns_known_options[i].no_aggregation = no_aggregation;
123         return 1;
124 }
125
126 static int
127 inplace_cb_reply_register_generic(inplace_cb_reply_func_type* cb,
128         enum inplace_cb_list_type type, void* cb_arg, struct module_env* env)
129 {
130         struct inplace_cb_reply* callback;
131         struct inplace_cb_reply** prevp;
132         if(env->worker) {
133                 log_err("invalid edns callback registration: "
134                         "trying to register callback after module init phase");
135                 return 0;
136         }
137
138         callback = (struct inplace_cb_reply*)calloc(1, sizeof(*callback));
139         if(callback == NULL) {
140                 log_err("out of memory during edns callback registration.");
141                 return 0;
142         }
143         callback->next = NULL;
144         callback->cb = cb;
145     callback->cb_arg = cb_arg;
146         
147         prevp = (struct inplace_cb_reply**) &env->inplace_cb_lists[type];
148         /* append at end of list */
149         while(*prevp != NULL)
150                 prevp = &((*prevp)->next);
151         *prevp = callback;
152         return 1;
153 }
154
155 int
156 inplace_cb_reply_register(inplace_cb_reply_func_type* cb, void* cb_arg,
157         struct module_env* env)
158 {
159         return inplace_cb_reply_register_generic(cb, inplace_cb_reply, cb_arg,
160                 env);
161 }
162
163 int
164 inplace_cb_reply_cache_register(inplace_cb_reply_func_type* cb, void* cb_arg,
165         struct module_env* env)
166 {
167         return inplace_cb_reply_register_generic(cb, inplace_cb_reply_cache,
168                 cb_arg, env);
169 }
170
171 int
172 inplace_cb_reply_local_register(inplace_cb_reply_func_type* cb, void* cb_arg,
173         struct module_env* env)
174 {
175         return inplace_cb_reply_register_generic(cb, inplace_cb_reply_local,
176                 cb_arg, env);
177 }
178
179 int
180 inplace_cb_reply_servfail_register(inplace_cb_reply_func_type* cb, void* cb_arg,
181         struct module_env* env)
182 {
183         return inplace_cb_reply_register_generic(cb, inplace_cb_reply_servfail,
184                 cb_arg, env);
185 }
186
187 static void
188 inplace_cb_reply_delete_generic(struct module_env* env,
189         enum inplace_cb_list_type type)
190 {
191         struct inplace_cb_reply* curr = env->inplace_cb_lists[type];
192         struct inplace_cb_reply* tmp;
193         /* delete list */
194         while(curr) {
195                 tmp = curr->next;
196                 free(curr);
197                 curr = tmp;
198         }
199         /* update head pointer */
200         env->inplace_cb_lists[type] = NULL;
201 }
202
203 void inplace_cb_reply_delete(struct module_env* env)
204 {
205         inplace_cb_reply_delete_generic(env, inplace_cb_reply);
206 }
207
208 void inplace_cb_reply_cache_delete(struct module_env* env)
209 {
210         inplace_cb_reply_delete_generic(env, inplace_cb_reply_cache);
211 }
212
213 void inplace_cb_reply_servfail_delete(struct module_env* env)
214 {
215         inplace_cb_reply_delete_generic(env, inplace_cb_reply_servfail);
216 }
217
218 int
219 inplace_cb_query_register(inplace_cb_query_func_type* cb, void* cb_arg,
220         struct module_env* env)
221 {
222         struct inplace_cb_query* callback;
223         struct inplace_cb_query** prevp;
224         if(env->worker) {
225                 log_err("invalid edns callback registration: "
226                         "trying to register callback after module init phase");
227                 return 0;
228         }
229
230         callback = (struct inplace_cb_query*)calloc(1, sizeof(*callback));
231         if(callback == NULL) {
232                 log_err("out of memory during edns callback registration.");
233                 return 0;
234         }
235         callback->next = NULL;
236         callback->cb = cb;
237     callback->cb_arg = cb_arg;
238         
239         prevp = (struct inplace_cb_query**)
240                 &env->inplace_cb_lists[inplace_cb_query];
241         /* append at end of list */
242         while(*prevp != NULL)
243                 prevp = &((*prevp)->next);
244         *prevp = callback;
245         return 1;
246 }
247
248 void
249 inplace_cb_query_delete(struct module_env* env)
250 {
251         struct inplace_cb_query* curr = env->inplace_cb_lists[inplace_cb_query];
252         struct inplace_cb_query* tmp;
253         /* delete list */
254         while(curr) {
255                 tmp = curr->next;
256                 free(curr);
257                 curr = tmp;
258         }
259         /* update head pointer */
260         env->inplace_cb_lists[inplace_cb_query] = NULL;
261 }
262
263 void
264 inplace_cb_lists_delete(struct module_env* env)
265 {
266     inplace_cb_reply_delete(env);
267     inplace_cb_reply_cache_delete(env);
268     inplace_cb_reply_servfail_delete(env);
269     inplace_cb_query_delete(env);
270 }
271
272 struct edns_known_option*
273 edns_option_is_known(uint16_t opt_code, struct module_env* env)
274 {
275         size_t i;
276         for(i=0; i<env->edns_known_options_num; i++)
277                 if(env->edns_known_options[i].opt_code == opt_code)
278                         return env->edns_known_options + i;
279         return NULL;
280 }
281
282 int
283 edns_bypass_cache_stage(struct edns_option* list, struct module_env* env)
284 {
285         size_t i;
286         for(; list; list=list->next)
287                 for(i=0; i<env->edns_known_options_num; i++)
288                         if(env->edns_known_options[i].opt_code == list->opt_code &&
289                                 env->edns_known_options[i].bypass_cache_stage == 1)
290                                         return 1;
291         return 0;
292 }
293
294 int
295 edns_unique_mesh_state(struct edns_option* list, struct module_env* env)
296 {
297         size_t i;
298         for(; list; list=list->next)
299                 for(i=0; i<env->edns_known_options_num; i++)
300                         if(env->edns_known_options[i].opt_code == list->opt_code &&
301                                 env->edns_known_options[i].no_aggregation == 1)
302                                         return 1;
303         return 0;
304 }
305
306 void
307 log_edns_known_options(enum verbosity_value level, struct module_env* env)
308 {
309         size_t i;
310         char str[32], *s;
311         size_t slen;
312         if(env->edns_known_options_num > 0 && verbosity >= level) {
313                 verbose(level, "EDNS known options:");
314                 verbose(level, "  Code:    Bypass_cache_stage: Aggregate_mesh:");
315                 for(i=0; i<env->edns_known_options_num; i++) {
316                         s = str;
317                         slen = sizeof(str);
318                         (void)sldns_wire2str_edns_option_code_print(&s, &slen,
319                                 env->edns_known_options[i].opt_code);
320                         verbose(level, "  %-8.8s %-19s %-15s", str,
321                                 env->edns_known_options[i].bypass_cache_stage?"YES":"NO",
322                                 env->edns_known_options[i].no_aggregation?"NO":"YES");
323                 }
324         }
325 }