4c75e3aa0f
Approved by: re (kib)
249 lines
7.1 KiB
C
249 lines
7.1 KiB
C
/*
|
|
* util/module.c - module interface
|
|
*
|
|
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
|
*
|
|
* This software is open source.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* Neither the name of the NLNET LABS nor the names of its contributors may
|
|
* be used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
/**
|
|
* \file
|
|
* Implementation of module.h.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "util/module.h"
|
|
#include "sldns/wire2str.h"
|
|
|
|
const char*
|
|
strextstate(enum module_ext_state s)
|
|
{
|
|
switch(s) {
|
|
case module_state_initial: return "module_state_initial";
|
|
case module_wait_reply: return "module_wait_reply";
|
|
case module_wait_module: return "module_wait_module";
|
|
case module_restart_next: return "module_restart_next";
|
|
case module_wait_subquery: return "module_wait_subquery";
|
|
case module_error: return "module_error";
|
|
case module_finished: return "module_finished";
|
|
}
|
|
return "bad_extstate_value";
|
|
}
|
|
|
|
const char*
|
|
strmodulevent(enum module_ev e)
|
|
{
|
|
switch(e) {
|
|
case module_event_new: return "module_event_new";
|
|
case module_event_pass: return "module_event_pass";
|
|
case module_event_reply: return "module_event_reply";
|
|
case module_event_noreply: return "module_event_noreply";
|
|
case module_event_capsfail: return "module_event_capsfail";
|
|
case module_event_moddone: return "module_event_moddone";
|
|
case module_event_error: return "module_event_error";
|
|
}
|
|
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;
|
|
}
|
|
|
|
int
|
|
inplace_cb_register(void* cb, enum inplace_cb_list_type type, void* cbarg,
|
|
struct module_env* env, int id)
|
|
{
|
|
struct inplace_cb* callback;
|
|
struct inplace_cb** prevp;
|
|
if(env->worker) {
|
|
log_err("invalid edns callback registration: "
|
|
"trying to register callback after module init phase");
|
|
return 0;
|
|
}
|
|
|
|
callback = (struct inplace_cb*)calloc(1, sizeof(*callback));
|
|
if(callback == NULL) {
|
|
log_err("out of memory during edns callback registration.");
|
|
return 0;
|
|
}
|
|
callback->id = id;
|
|
callback->next = NULL;
|
|
callback->cb = cb;
|
|
callback->cb_arg = cbarg;
|
|
|
|
prevp = (struct inplace_cb**) &env->inplace_cb_lists[type];
|
|
/* append at end of list */
|
|
while(*prevp != NULL)
|
|
prevp = &((*prevp)->next);
|
|
*prevp = callback;
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
inplace_cb_delete(struct module_env* env, enum inplace_cb_list_type type,
|
|
int id)
|
|
{
|
|
struct inplace_cb* temp = env->inplace_cb_lists[type];
|
|
struct inplace_cb* prev = NULL;
|
|
|
|
while(temp) {
|
|
if(temp->id == id) {
|
|
if(!prev) {
|
|
env->inplace_cb_lists[type] = temp->next;
|
|
free(temp);
|
|
temp = env->inplace_cb_lists[type];
|
|
}
|
|
else {
|
|
prev->next = temp->next;
|
|
free(temp);
|
|
temp = prev->next;
|
|
}
|
|
}
|
|
else {
|
|
prev = temp;
|
|
temp = temp->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
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
|
|
unique_mesh_state(struct edns_option* list, struct module_env* env)
|
|
{
|
|
size_t i;
|
|
if(env->unique_mesh)
|
|
return 1;
|
|
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");
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
copy_state_to_super(struct module_qstate* qstate, int ATTR_UNUSED(id),
|
|
struct module_qstate* super)
|
|
{
|
|
/* Overwrite super's was_ratelimited only when it was not set */
|
|
if(!super->was_ratelimited) {
|
|
super->was_ratelimited = qstate->was_ratelimited;
|
|
}
|
|
}
|