summaryrefslogtreecommitdiff
path: root/util/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/module.c')
-rw-r--r--util/module.c254
1 files changed, 254 insertions, 0 deletions
diff --git a/util/module.c b/util/module.c
index 09e276c30152..cc3328b13c9b 100644
--- a/util/module.c
+++ b/util/module.c
@@ -39,6 +39,7 @@
#include "config.h"
#include "util/module.h"
+#include "sldns/wire2str.h"
const char*
strextstate(enum module_ext_state s)
@@ -69,3 +70,256 @@ strmodulevent(enum module_ev e)
}
return "bad_event_value";
}
+
+int
+edns_known_options_init(struct module_env* env)
+{
+ env->edns_known_options_num = 0;
+ env->edns_known_options = (struct edns_known_option*)calloc(
+ MAX_KNOWN_EDNS_OPTS, sizeof(struct edns_known_option));
+ if(!env->edns_known_options) return 0;
+ return 1;
+}
+
+void
+edns_known_options_delete(struct module_env* env)
+{
+ free(env->edns_known_options);
+ env->edns_known_options = NULL;
+ env->edns_known_options_num = 0;
+}
+
+int
+edns_register_option(uint16_t opt_code, int bypass_cache_stage,
+ int no_aggregation, struct module_env* env)
+{
+ size_t i;
+ if(env->worker) {
+ log_err("invalid edns registration: "
+ "trying to register option after module init phase");
+ return 0;
+ }
+
+ /**
+ * Checking if we are full first is faster but it does not provide
+ * the option to change the flags when the array is full.
+ * It only impacts unbound initialization, leave it for now.
+ */
+ /* Check if the option is already registered. */
+ for(i=0; i<env->edns_known_options_num; i++)
+ if(env->edns_known_options[i].opt_code == opt_code)
+ break;
+ /* If it is not yet registered check if we have space to add a new one. */
+ if(i == env->edns_known_options_num) {
+ if(env->edns_known_options_num >= MAX_KNOWN_EDNS_OPTS) {
+ log_err("invalid edns registration: maximum options reached");
+ return 0;
+ }
+ env->edns_known_options_num++;
+ }
+ env->edns_known_options[i].opt_code = opt_code;
+ env->edns_known_options[i].bypass_cache_stage = bypass_cache_stage;
+ env->edns_known_options[i].no_aggregation = no_aggregation;
+ return 1;
+}
+
+static int
+inplace_cb_reply_register_generic(inplace_cb_reply_func_t* cb,
+ enum inplace_cb_list_type type, void* cb_arg, struct module_env* env)
+{
+ struct inplace_cb_reply* callback;
+ struct inplace_cb_reply** prevp;
+ if(env->worker) {
+ log_err("invalid edns callback registration: "
+ "trying to register callback after module init phase");
+ return 0;
+ }
+
+ callback = (struct inplace_cb_reply*)calloc(1, sizeof(*callback));
+ if(callback == NULL) {
+ log_err("out of memory during edns callback registration.");
+ return 0;
+ }
+ callback->next = NULL;
+ callback->cb = cb;
+ callback->cb_arg = cb_arg;
+
+ prevp = (struct inplace_cb_reply**) &env->inplace_cb_lists[type];
+ /* append at end of list */
+ while(*prevp != NULL)
+ prevp = &((*prevp)->next);
+ *prevp = callback;
+ return 1;
+}
+
+int
+inplace_cb_reply_register(inplace_cb_reply_func_t* cb, void* cb_arg,
+ struct module_env* env)
+{
+ return inplace_cb_reply_register_generic(cb, inplace_cb_reply, cb_arg,
+ env);
+}
+
+int
+inplace_cb_reply_cache_register(inplace_cb_reply_func_t* cb, void* cb_arg,
+ struct module_env* env)
+{
+ return inplace_cb_reply_register_generic(cb, inplace_cb_reply_cache,
+ cb_arg, env);
+}
+
+int
+inplace_cb_reply_local_register(inplace_cb_reply_func_t* cb, void* cb_arg,
+ struct module_env* env)
+{
+ return inplace_cb_reply_register_generic(cb, inplace_cb_reply_local,
+ cb_arg, env);
+}
+
+int
+inplace_cb_reply_servfail_register(inplace_cb_reply_func_t* cb, void* cb_arg,
+ struct module_env* env)
+{
+ return inplace_cb_reply_register_generic(cb, inplace_cb_reply_servfail,
+ cb_arg, env);
+}
+
+static void
+inplace_cb_reply_delete_generic(struct module_env* env,
+ enum inplace_cb_list_type type)
+{
+ struct inplace_cb_reply* curr = env->inplace_cb_lists[type];
+ struct inplace_cb_reply* tmp;
+ /* delete list */
+ while(curr) {
+ tmp = curr->next;
+ free(curr);
+ curr = tmp;
+ }
+ /* update head pointer */
+ env->inplace_cb_lists[type] = NULL;
+}
+
+void inplace_cb_reply_delete(struct module_env* env)
+{
+ inplace_cb_reply_delete_generic(env, inplace_cb_reply);
+}
+
+void inplace_cb_reply_cache_delete(struct module_env* env)
+{
+ inplace_cb_reply_delete_generic(env, inplace_cb_reply_cache);
+}
+
+void inplace_cb_reply_servfail_delete(struct module_env* env)
+{
+ inplace_cb_reply_delete_generic(env, inplace_cb_reply_servfail);
+}
+
+int
+inplace_cb_query_register(inplace_cb_query_func_t* cb, void* cb_arg,
+ struct module_env* env)
+{
+ struct inplace_cb_query* callback;
+ struct inplace_cb_query** prevp;
+ if(env->worker) {
+ log_err("invalid edns callback registration: "
+ "trying to register callback after module init phase");
+ return 0;
+ }
+
+ callback = (struct inplace_cb_query*)calloc(1, sizeof(*callback));
+ if(callback == NULL) {
+ log_err("out of memory during edns callback registration.");
+ return 0;
+ }
+ callback->next = NULL;
+ callback->cb = cb;
+ callback->cb_arg = cb_arg;
+
+ prevp = (struct inplace_cb_query**)
+ &env->inplace_cb_lists[inplace_cb_query];
+ /* append at end of list */
+ while(*prevp != NULL)
+ prevp = &((*prevp)->next);
+ *prevp = callback;
+ return 1;
+}
+
+void
+inplace_cb_query_delete(struct module_env* env)
+{
+ struct inplace_cb_query* curr = env->inplace_cb_lists[inplace_cb_query];
+ struct inplace_cb_query* tmp;
+ /* delete list */
+ while(curr) {
+ tmp = curr->next;
+ free(curr);
+ curr = tmp;
+ }
+ /* update head pointer */
+ env->inplace_cb_lists[inplace_cb_query] = NULL;
+}
+
+void
+inplace_cb_lists_delete(struct module_env* env)
+{
+ inplace_cb_reply_delete(env);
+ inplace_cb_reply_cache_delete(env);
+ inplace_cb_reply_servfail_delete(env);
+ inplace_cb_query_delete(env);
+}
+
+struct edns_known_option*
+edns_option_is_known(uint16_t opt_code, struct module_env* env)
+{
+ size_t i;
+ for(i=0; i<env->edns_known_options_num; i++)
+ if(env->edns_known_options[i].opt_code == opt_code)
+ return env->edns_known_options + i;
+ return NULL;
+}
+
+int
+edns_bypass_cache_stage(struct edns_option* list, struct module_env* env)
+{
+ size_t i;
+ for(; list; list=list->next)
+ for(i=0; i<env->edns_known_options_num; i++)
+ if(env->edns_known_options[i].opt_code == list->opt_code &&
+ env->edns_known_options[i].bypass_cache_stage == 1)
+ return 1;
+ return 0;
+}
+
+int
+edns_unique_mesh_state(struct edns_option* list, struct module_env* env)
+{
+ size_t i;
+ for(; list; list=list->next)
+ for(i=0; i<env->edns_known_options_num; i++)
+ if(env->edns_known_options[i].opt_code == list->opt_code &&
+ env->edns_known_options[i].no_aggregation == 1)
+ return 1;
+ return 0;
+}
+
+void
+log_edns_known_options(enum verbosity_value level, struct module_env* env)
+{
+ size_t i;
+ char str[32], *s;
+ size_t slen;
+ if(env->edns_known_options_num > 0 && verbosity >= level) {
+ verbose(level, "EDNS known options:");
+ verbose(level, " Code: Bypass_cache_stage: Aggregate_mesh:");
+ for(i=0; i<env->edns_known_options_num; i++) {
+ s = str;
+ slen = sizeof(str);
+ (void)sldns_wire2str_edns_option_code_print(&s, &slen,
+ env->edns_known_options[i].opt_code);
+ verbose(level, " %-8.8s %-19s %-15s", str,
+ env->edns_known_options[i].bypass_cache_stage?"YES":"NO",
+ env->edns_known_options[i].no_aggregation?"NO":"YES");
+ }
+ }
+}