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 } 249