]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/unbound/util/module.c
Fix multiple vulnerabilities in unbound.
[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 int
127 inplace_cb_register(void* cb, enum inplace_cb_list_type type, void* cbarg,
128         struct module_env* env, int id)
129 {
130         struct inplace_cb* callback;
131         struct inplace_cb** 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*)calloc(1, sizeof(*callback));
139         if(callback == NULL) {
140                 log_err("out of memory during edns callback registration.");
141                 return 0;
142         }
143         callback->id = id;
144         callback->next = NULL;
145         callback->cb = cb;
146         callback->cb_arg = cbarg;
147         
148         prevp = (struct inplace_cb**) &env->inplace_cb_lists[type];
149         /* append at end of list */
150         while(*prevp != NULL)
151                 prevp = &((*prevp)->next);
152         *prevp = callback;
153         return 1;
154 }
155
156 void
157 inplace_cb_delete(struct module_env* env, enum inplace_cb_list_type type,
158         int id)
159 {
160         struct inplace_cb* temp = env->inplace_cb_lists[type];
161         struct inplace_cb* prev = NULL;
162
163         while(temp) {
164                 if(temp->id == id) {
165                         if(!prev) {
166                                 env->inplace_cb_lists[type] = temp->next;
167                                 free(temp);
168                                 temp = env->inplace_cb_lists[type];
169                         }
170                         else {
171                                 prev->next = temp->next;
172                                 free(temp);
173                                 temp = prev->next;
174                         }
175                 }
176                 else {
177                         prev = temp;
178                         temp = temp->next;
179                 }
180         }
181 }
182
183 struct edns_known_option*
184 edns_option_is_known(uint16_t opt_code, struct module_env* env)
185 {
186         size_t i;
187         for(i=0; i<env->edns_known_options_num; i++)
188                 if(env->edns_known_options[i].opt_code == opt_code)
189                         return env->edns_known_options + i;
190         return NULL;
191 }
192
193 int
194 edns_bypass_cache_stage(struct edns_option* list, struct module_env* env)
195 {
196         size_t i;
197         for(; list; list=list->next)
198                 for(i=0; i<env->edns_known_options_num; i++)
199                         if(env->edns_known_options[i].opt_code == list->opt_code &&
200                                 env->edns_known_options[i].bypass_cache_stage == 1)
201                                         return 1;
202         return 0;
203 }
204
205 int
206 unique_mesh_state(struct edns_option* list, struct module_env* env)
207 {
208         size_t i;
209         if(env->unique_mesh)
210                 return 1;
211         for(; list; list=list->next)
212                 for(i=0; i<env->edns_known_options_num; i++)
213                         if(env->edns_known_options[i].opt_code == list->opt_code &&
214                                 env->edns_known_options[i].no_aggregation == 1)
215                                         return 1;
216         return 0;
217 }
218
219 void
220 log_edns_known_options(enum verbosity_value level, struct module_env* env)
221 {
222         size_t i;
223         char str[32], *s;
224         size_t slen;
225         if(env->edns_known_options_num > 0 && verbosity >= level) {
226                 verbose(level, "EDNS known options:");
227                 verbose(level, "  Code:    Bypass_cache_stage: Aggregate_mesh:");
228                 for(i=0; i<env->edns_known_options_num; i++) {
229                         s = str;
230                         slen = sizeof(str);
231                         (void)sldns_wire2str_edns_option_code_print(&s, &slen,
232                                 env->edns_known_options[i].opt_code);
233                         verbose(level, "  %-8.8s %-19s %-15s", str,
234                                 env->edns_known_options[i].bypass_cache_stage?"YES":"NO",
235                                 env->edns_known_options[i].no_aggregation?"NO":"YES");
236                 }
237         }
238 }
239
240 void
241 copy_state_to_super(struct module_qstate* qstate, int ATTR_UNUSED(id),
242         struct module_qstate* super)
243 {
244         /* Overwrite super's was_ratelimited only when it was not set */
245         if(!super->was_ratelimited) {
246                 super->was_ratelimited = qstate->was_ratelimited;
247         }
248 }