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)
# 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
#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. */
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.
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;
+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.
# 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
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
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 */
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);
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);
}
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;
/**
* 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
* @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.
* 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.
*/
*
* @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.
*/
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);
}
}
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;
* @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.
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);
config_delstrlist(cfg->donotqueryaddrs);
free(cfg->identity);
free(cfg->version);
+ free(cfg->module_conf);
free(cfg);
}
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;
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 */
%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 ;
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
{
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));
struct mesh_state;
/** Maximum number of modules in operation */
-#define MAX_MODULE 2
+#define MAX_MODULE 5
/**
* Module environment.
* @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.
* @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.
* @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.
--- /dev/null
+/*
+ * 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";
+}
--- /dev/null
+/*
+ * 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 */