module configuration option.

git-svn-id: file:///svn/unbound/trunk@468 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-08-01 11:17:30 +00:00
parent 39e8652152
commit ac895c6d35
18 changed files with 360 additions and 25 deletions

View file

@ -53,8 +53,8 @@ LINTFLAGS+="-DBN_ULONG=unsigned long" -Dkrb5_int32=int "-Dkrb5_ui_4=unsigned int
INSTALL=$(srcdir)/install-sh
COMMON_SRC=$(wildcard services/*.c services/cache/*.c util/*.c \
util/data/*.c util/storage/*.c iterator/*.c) util/configparser.c \
util/configlexer.c testcode/checklocks.c
util/data/*.c util/storage/*.c iterator/*.c validator/*.c) \
util/configparser.c util/configlexer.c testcode/checklocks.c
COMMON_OBJ=$(addprefix $(BUILD),$(COMMON_SRC:.c=.o))
COMPAT_OBJ=$(addprefix $(BUILD)compat/,$(LIBOBJS))
UNITTEST_SRC=$(wildcard testcode/unit*.c) testcode/readhex.c $(COMMON_SRC)

View file

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.57)
AC_INIT(unbound, 0.4, wouter@nlnetlabs.nl, unbound)
AC_INIT(unbound, 0.5, wouter@nlnetlabs.nl, unbound)
CFLAGS=
AC_AIX

View file

@ -54,6 +54,7 @@
#include "services/cache/infra.h"
#include "util/module.h"
#include "iterator/iterator.h"
#include "validator/validator.h"
#include <signal.h>
/** How many quit requests happened. */
@ -148,6 +149,93 @@ daemon_open_shared_ports(struct daemon* daemon)
return 1;
}
/** count number of modules (words) in the string */
static int
count_modules(const char* s)
{
int num = 0;
if(!s)
return 0;
while(*s) {
/* skip whitespace */
while(*s && isspace(*s))
s++;
if(*s && !isspace(*s)) {
/* skip identifier */
num++;
while(*s && !isspace(*s))
s++;
}
}
return num;
}
/**
* Get funcblock for module name
* @param str: string with module name. Advanced to next value.
* @return funcblock or NULL on error.
*/
static struct module_func_block*
daemon_module_factory(const char** str)
{
/* these are the modules available */
int num = 2;
const char* names[] = {"iterator", "validator", NULL};
struct module_func_block* (*fb[])(void) =
{&iter_get_funcblock, &val_get_funcblock, NULL};
int i;
const char* s = *str;
while(*s && isspace(*s))
s++;
for(i=0; i<num; i++) {
if(strncmp(names[i], s, strlen(names[i])) == 0) {
s += strlen(names[i]);
*str = s;
return (*fb[i])();
}
}
return NULL;
}
/**
* Read config file module settings and set up the modfunc block
* @param daemon: the daemon.
* @return false on error
*/
static int
daemon_config_modules(struct daemon* daemon)
{
const char* str = daemon->cfg->module_conf;
int i;
verbose(VERB_DETAIL, "module config: \"%s\"", str);
daemon->num_modules = count_modules(str);
if(daemon->num_modules == 0) {
log_err("error: no modules specified");
return 0;
}
if(daemon->num_modules > MAX_MODULE) {
log_err("error: too many modules (%d max %d)",
daemon->num_modules, MAX_MODULE);
return 0;
}
daemon->modfunc = (struct module_func_block**)calloc((size_t)
daemon->num_modules, sizeof(struct module_func_block*));
if(!daemon->modfunc) {
log_err("out of memory");
return 0;
}
for(i=0; i<daemon->num_modules; i++) {
daemon->modfunc[i] = daemon_module_factory(&str);
if(!daemon->modfunc[i]) {
log_err("Unknown value for first module in: '%s'",
str);
return 0;
}
}
return 1;
}
/**
* Desetup the modules, deinit, delete.
* @param daemon: the daemon.
@ -174,13 +262,9 @@ static void daemon_setup_modules(struct daemon* daemon)
if(daemon->num_modules != 0)
daemon_desetup_modules(daemon);
/* fixed setup of the modules */
daemon->num_modules = 1;
daemon->modfunc = (struct module_func_block**)calloc((size_t)
daemon->num_modules, sizeof(struct module_func_block*));
if(!daemon->modfunc) {
fatal_exit("malloc failure allocating function callbacks");
if(!daemon_config_modules(daemon)) {
fatal_exit("failed to setup modules");
}
daemon->modfunc[0] = iter_get_funcblock();
daemon->env->cfg = daemon->cfg;
daemon->env->alloc = &daemon->superalloc;
daemon->env->worker = NULL;

View file

@ -1,3 +1,8 @@
1 August 2007: Wouter
- set version to 0.5
- module work for module to module interconnections.
- config of modules.
31 July 2007: Wouter
- updated plan
- release 0.4 tag.

View file

@ -147,6 +147,10 @@ server:
# DNS port, use "1.2.3.4@123" to block port 123 for 1.2.3.4.
# do-not-query-address: 127.0.0.1
# do-not-query-address: ::1
# module configuration of the server. A string with identifiers
# separated by spaces. "iterator" or "validator iterator"
# module-config: "validator iterator"
# Stub zones.
# Create entries like below, to make all queries for 'example.com' and

View file

@ -183,6 +183,11 @@ Will trust glue only if it is within the servers authority. Default is on.
Do not query the given IP address. Can be IP4 or IP6. By default the
DNS port is blocked for that address. Appending the character '@' and then
the portnumber will block other port numbers.
.It \fBmodule-config:\fR <"module names">
Module configuration, a list of module names separated by spaces, surround
the string with quotes (""). The modules can be validator, iterator.
Setting this to "iterator" will result in a non-validating server.
Setting this to "validator iterator" will turn on validation.
.El
.Ss Stub Zone Options

View file

@ -81,15 +81,14 @@ static void
iter_deinit(struct module_env* env, int id)
{
struct iter_env* iter_env;
if(!env || !env->modinfo)
if(!env || !env->modinfo || !env->modinfo[id])
return;
iter_env = (struct iter_env*)env->modinfo[id];
free(iter_env->target_fetch_policy);
hints_delete(iter_env->hints);
forwards_delete(iter_env->fwds);
donotq_delete(iter_env->donotq);
if(iter_env)
free(iter_env);
free(iter_env);
}
/** new query for iterator */
@ -1015,7 +1014,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
outq = (*qstate->env->send_query)(
iq->qchase.qname, iq->qchase.qname_len,
iq->qchase.qtype, iq->qchase.qclass,
iq->chase_flags, 1, &target->addr, target->addrlen, qstate);
iq->chase_flags, EDNS_DO|BIT_CD,
&target->addr, target->addrlen, qstate);
if(!outq) {
log_err("error sending query to auth server; skip this address");
log_addr("error for address:", &target->addr, target->addrlen);

View file

@ -69,6 +69,11 @@ mesh_state_compare(const void* ap, const void* bp)
if(!(a->s.query_flags&BIT_RD) && (b->s.query_flags&BIT_RD))
return 1;
if((a->s.query_flags&BIT_CD) && !(b->s.query_flags&BIT_CD))
return -1;
if(!(a->s.query_flags&BIT_CD) && (b->s.query_flags&BIT_CD))
return 1;
return query_info_compare(&a->s.qinfo, &b->s.qinfo);
}
@ -222,7 +227,7 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
return NULL;
}
/* remove all weird bits from qflags */
mstate->s.query_flags = (qflags & BIT_RD);
mstate->s.query_flags = (qflags & (BIT_RD|BIT_CD));
mstate->s.reply = NULL;
mstate->s.region = region;
mstate->s.curmod = 0;

View file

@ -95,7 +95,7 @@ struct mesh_area {
/**
* A mesh query state
* Unique per qname, qtype, qclass (from the qstate).
* And RD flag; in case a client turns it off.
* And RD / CD flag; in case a client turns it off.
* And priming queries are different from ordinary queries (because of hints).
*
* The entire structure is allocated in a region, this region is the qstate
@ -226,7 +226,7 @@ void mesh_detach_subs(struct module_qstate* qstate);
* @param qstate: the state to find mesh state, and that wants to receive
* the results from the new subquery.
* @param qinfo: what to query for (copied).
* @param qflags: what flags to use (RD flag or not).
* @param qflags: what flags to use (RD / CD flag or not).
* @param prime: if it is a (stub) priming query.
* @param newq: If the new subquery needs initialisation, it is returned,
* otherwise NULL is returned.
@ -281,7 +281,7 @@ void mesh_state_delete(struct module_qstate* qstate);
* Does not put the mesh state into rbtrees and so on.
* @param env: module environment to set.
* @param qinfo: query info that the mesh is for.
* @param qflags: flags for query (RD flag).
* @param qflags: flags for query (RD / CD flag).
* @param prime: if true, it is a priming query, set is_priming on mesh state.
* @return: new mesh state or NULL on allocation error.
*/
@ -301,7 +301,7 @@ void mesh_state_cleanup(struct mesh_state* mstate);
*
* @param mesh: the mesh area to look in.
* @param qinfo: what query
* @param qflags: if RD bit is set or not.
* @param qflags: if RD / CD bit is set or not.
* @param prime: if it is a priming query.
* @return: mesh state or NULL if not found.
*/

View file

@ -921,8 +921,10 @@ serviced_encode(struct serviced_query* sq, ldns_buffer* buff, int with_edns)
edns.edns_version = EDNS_ADVERTISED_VERSION;
edns.udp_size = EDNS_ADVERTISED_SIZE;
edns.bits = 0;
if(sq->dnssec)
if(sq->dnssec & EDNS_DO)
edns.bits = EDNS_DO;
if(sq->dnssec & BIT_CD)
LDNS_CD_SET(ldns_buffer_begin(buff));
attach_edns_record(buff, &edns);
}
}

View file

@ -210,7 +210,7 @@ struct serviced_query {
uint8_t* qbuf;
/** length of qbuf. */
size_t qbuflen;
/** If an EDNS section is included, the DO bit will be turned on. */
/** If an EDNS section is included, the DO/CD bit will be turned on. */
int dnssec;
/** where to send it */
struct sockaddr_storage addr;
@ -337,6 +337,8 @@ void pending_delete(struct outside_network* outnet, struct pending* p);
* @param qclass: query class. (host format)
* @param flags: flags u16 (host format), includes opcode, CD bit.
* @param dnssec: if set, DO bit is set in EDNS queries.
* If the value includes BIT_CD, CD bit is set when in EDNS queries.
* If the value includes BIT_DO, DO bit is set when in EDNS queries.
* @param callback: callback function.
* @param callback_arg: user argument to callback function.
* @param addr: to which server to send the query.

View file

@ -111,6 +111,7 @@ config_create()
cfg->hide_version = 0;
cfg->identity = NULL;
cfg->version = NULL;
if(!(cfg->module_conf = strdup("iterator"))) goto error_exit;
return cfg;
error_exit:
config_delete(cfg);
@ -203,6 +204,7 @@ config_delete(struct config_file* cfg)
config_delstrlist(cfg->donotqueryaddrs);
free(cfg->identity);
free(cfg->version);
free(cfg->module_conf);
free(cfg);
}

View file

@ -135,6 +135,9 @@ struct config_file {
char* identity;
/** version, package version returned if "". */
char* version;
/** the module configuration string */
char* module_conf;
/** daemonize, i.e. fork into the background. */
int do_daemonize;

View file

@ -141,6 +141,7 @@ hide-identity{COLON} { YDOUT; return VAR_HIDE_IDENTITY;}
hide-version{COLON} { YDOUT; return VAR_HIDE_VERSION;}
identity{COLON} { YDOUT; return VAR_IDENTITY;}
version{COLON} { YDOUT; return VAR_VERSION;}
module-conf{COLON} { YDOUT; return VAR_MODULE_CONF;}
{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;}
/* Quoted strings. Strip leading and ending quotes */

View file

@ -79,7 +79,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_HARDEN_SHORT_BUFSIZE VAR_HARDEN_LARGE_QUERIES
%token VAR_FORWARD_ZONE VAR_FORWARD_HOST VAR_FORWARD_ADDR
%token VAR_DO_NOT_QUERY_ADDRESS VAR_HIDE_IDENTITY VAR_HIDE_VERSION
%token VAR_IDENTITY VAR_VERSION VAR_HARDEN_GLUE
%token VAR_IDENTITY VAR_VERSION VAR_HARDEN_GLUE VAR_MODULE_CONF
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -112,7 +112,7 @@ content_server: server_num_threads | server_verbosity | server_port |
server_harden_short_bufsize | server_harden_large_queries |
server_do_not_query_address | server_hide_identity |
server_hide_version | server_identity | server_version |
server_harden_glue
server_harden_glue | server_module_conf
;
stubstart: VAR_STUB_ZONE
{
@ -462,6 +462,13 @@ server_do_not_query_address: VAR_DO_NOT_QUERY_ADDRESS STRING
yyerror("out of memory");
}
;
server_module_conf: VAR_MODULE_CONF STRING
{
OUTYY(("P(server_module_conf:%s)\n", $2));
free(cfg_parser->cfg->module_conf);
cfg_parser->cfg->module_conf = $2;
}
;
stub_name: VAR_NAME STRING
{
OUTYY(("P(name:%s)\n", $2));

View file

@ -58,7 +58,7 @@ struct mesh_area;
struct mesh_state;
/** Maximum number of modules in operation */
#define MAX_MODULE 2
#define MAX_MODULE 5
/**
* Module environment.
@ -105,7 +105,9 @@ struct module_env {
* @param qtype: query type. (host order)
* @param qclass: query class. (host order)
* @param flags: host order flags word, with opcode and CD bit.
* @param dnssec: if set, EDNS record will have DO bit set.
* @param dnssec: if set, EDNS record will have bits set.
* If EDNS_DO bit is set, DO bit is set in EDNS records.
* If BIT_CD is set, CD bit is set in queries with EDNS records.
* @param addr: where to.
* @param addrlen: length of addr.
* @param q: wich query state to reactivate upon return.
@ -143,7 +145,7 @@ struct module_env {
* @param qstate: the state to find mesh state, and that wants to
* receive the results from the new subquery.
* @param qinfo: what to query for (copied).
* @param qflags: what flags to use (RD flag or not).
* @param qflags: what flags to use (RD, CD flag or not).
* @param prime: if it is a (stub) priming query.
* @param newq: If the new subquery needs initialisation, it is
* returned, otherwise NULL is returned.
@ -314,6 +316,10 @@ struct module_func_block {
* @param ev: event that causes the module state machine to
* (re-)activate.
* @param qstate: the query state.
* Note that this method is not allowed to change the
* query state 'identity', that is query info, qflags,
* and priming status.
* Attach a subquery to get results to a different query.
* @param id: module id number that operate() is called on.
* @param outbound: if not NULL this event is due to the reply/timeout
* or error on this outbound query.

123
validator/validator.c Normal file
View file

@ -0,0 +1,123 @@
/*
* validator/validator.c - secure validator DNS query response module
*
* 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 REGENTS 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
*
* This file contains a module that performs validation of DNS queries.
* According to RFC 4034.
*/
#include "config.h"
#include "validator/validator.h"
#include "util/module.h"
#include "util/log.h"
/** validator init */
static int
val_init(struct module_env* env, int id)
{
struct val_env* val_env = (struct val_env*)calloc(1,
sizeof(struct val_env));
if(!val_env) {
log_err("malloc failure");
return 0;
}
env->modinfo[id] = (void*)val_env;
/*if(!val_apply_cfg(val_env, env->cfg)) {
log_err("validator: could not apply configuration settings.");
return 0;
}*/
return 1;
}
/** validator deinit */
static void
val_deinit(struct module_env* env, int id)
{
struct val_env* val_env;
if(!env || !env->modinfo || !env->modinfo[id])
return;
val_env = (struct val_env*)env->modinfo[id];
free(val_env);
}
/** validator operate on a query */
static void
val_operate(struct module_qstate* qstate, enum module_ev event, int id,
struct outbound_entry* outbound)
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
struct val_qstate* vq = (struct val_qstate*)qstate->minfo[id];
verbose(VERB_DETAIL, "validator[module %d] operate: extstate:%s "
"event:%s", id, strextstate(qstate->ext_state[id]),
strmodulevent(event));
if(vq) log_query_info(VERB_DETAIL, "iterator operate: query",
&qstate->qinfo);
(void)ve;
(void)outbound;
}
/** validator cleanup query state */
static void
val_clear(struct module_qstate* qstate, int id)
{
if(!qstate)
return;
/* everything is allocated in the region, so assign NULL */
qstate->minfo[id] = NULL;
}
/**
* The validator function block
*/
static struct module_func_block val_block = {
"validator",
&val_init, &val_deinit, &val_operate, &val_clear
};
struct module_func_block*
val_get_funcblock()
{
return &val_block;
}
const char*
val_state_to_string(enum val_state state)
{
switch(state) {
case VAL_STATE_INIT: return "VAL_STATE_INIT";
}
return "UNKNOWN VALIDATOR STATE";
}

86
validator/validator.h Normal file
View file

@ -0,0 +1,86 @@
/*
* validator/validator.h - secure validator DNS query response module
*
* 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 REGENTS 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
*
* This file contains a module that performs validation of DNS queries.
* According to RFC 4034.
*/
#ifndef VALIDATOR_VALIDATOR_H
#define VALIDATOR_VALIDATOR_H
struct module_func_block;
/**
* Global state for the validator.
*/
struct val_env {
/** global state placeholder */
int option;
};
/**
* State of the validator for a query.
*/
enum val_state {
/** initial state for validation */
VAL_STATE_INIT = 0
};
/**
* Per query state for the validator module.
*/
struct val_qstate {
/**
* State of the validator module.
*/
enum val_state state;
};
/**
* Get the validator function block.
* @return: function block with function pointers to validator methods.
*/
struct module_func_block* val_get_funcblock();
/**
* Get validator state as a string
* @param state: to convert
* @return constant string that is printable.
*/
const char* val_state_to_string(enum val_state state);
#endif /* VALIDATOR_VALIDATOR_H */