From: Wouter Wijngaards Date: Wed, 1 Aug 2007 11:17:30 +0000 (+0000) Subject: module configuration option. X-Git-Tag: release-0.5~173 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ac895c6d35824362a1e61d7e5e954e7c1ae71814;p=thirdparty%2Funbound.git module configuration option. git-svn-id: file:///svn/unbound/trunk@468 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/Makefile.in b/Makefile.in index ada1c6c31..5b9e9bc8a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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) diff --git a/configure.ac b/configure.ac index 61680f309..a35a0ec45 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/daemon/daemon.c b/daemon/daemon.c index f9873314e..b24a9f59f 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -54,6 +54,7 @@ #include "services/cache/infra.h" #include "util/module.h" #include "iterator/iterator.h" +#include "validator/validator.h" #include /** 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; icfg->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; inum_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; diff --git a/doc/Changelog b/doc/Changelog index 4a936b6d9..280d8bc4d 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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. diff --git a/doc/example.conf b/doc/example.conf index def4e1bca..49c636cc0 100644 --- a/doc/example.conf +++ b/doc/example.conf @@ -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 diff --git a/doc/unbound.conf.5 b/doc/unbound.conf.5 index 5c8245075..3811b3687 100644 --- a/doc/unbound.conf.5 +++ b/doc/unbound.conf.5 @@ -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 diff --git a/iterator/iterator.c b/iterator/iterator.c index f2cff2b47..2234f0657 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -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); diff --git a/services/mesh.c b/services/mesh.c index 3d8c48ea9..4abd77c9a 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -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; diff --git a/services/mesh.h b/services/mesh.h index dc260a615..82e1a92e4 100644 --- a/services/mesh.h +++ b/services/mesh.h @@ -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. */ diff --git a/services/outside_network.c b/services/outside_network.c index da0aec649..3cc81b9b0 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -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); } } diff --git a/services/outside_network.h b/services/outside_network.h index 8765c93e8..06555f863 100644 --- a/services/outside_network.h +++ b/services/outside_network.h @@ -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. diff --git a/util/config_file.c b/util/config_file.c index ef5a9b225..c803cebf2 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -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); } diff --git a/util/config_file.h b/util/config_file.h index 037695d13..0a66e25e4 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -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; diff --git a/util/configlexer.lex b/util/configlexer.lex index 1c6594f87..365b887b5 100644 --- a/util/configlexer.lex +++ b/util/configlexer.lex @@ -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 */ diff --git a/util/configparser.y b/util/configparser.y index 56b94412f..6e2e68875 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -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)); diff --git a/util/module.h b/util/module.h index 687aea63e..f6d7f058f 100644 --- a/util/module.h +++ b/util/module.h @@ -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. diff --git a/validator/validator.c b/validator/validator.c new file mode 100644 index 000000000..adf472aab --- /dev/null +++ b/validator/validator.c @@ -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"; +} diff --git a/validator/validator.h b/validator/validator.h new file mode 100644 index 000000000..b25dfc124 --- /dev/null +++ b/validator/validator.h @@ -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 */