- forward zone options in config file.
- forward per zone in iterator. takes precendence over stubs.
- fixup commithooks.
+ - removed forward-to and forward-to-port features, subsumed by
+ new forward zones.
+ - fix parser to handle absent server: clause.
+ - change untrusted rrset test to account for scrubber that is now
+ applied during the test (which removes the poison, by the way).
+ - feature, addresses can be specified with @portnumber, like nsd.conf.
+ - test config files changed over to new forwarder syntax.
27 June 2007: Wouter
- delete of mesh does a postorder traverse of the tree.
# Enable TCP, "yes" or "no".
# do-tcp: yes
- # Set this to configure unbound to act as a forwarder. All queries are
- # sent to the remote nameserver that will resolve them.
- # Set to "" to disable forwarding, or give ip-address to enable.
- # forward-to: ""
-
- # The port number to send forwarded queries to.
- # forward-to-port: 53
-
# if given, a chroot(2) is done to the given directory.
# i.e. you can chroot to the working directory, for example,
# for extra security, but make sure all files are in that directory.
# forward-zone:
# name: "example.com"
# forward-addr: 192.0.2.68
+# forward-addr: 192.0.2.73@5355 # forward to port 5355.
# forward-zone:
# name: "example.org"
# forward-host: fwd.example.com
Enable or disable whether UDP queries are answered. Default is yes.
.It \fBdo-tcp:\fR <yes or no>
Enable or disable whether TCP queries are answered. Default is yes.
-.It \fBforward-to:\fR <ip address>
-If set (not "") then forwarder mode is enabled. Default is "" (disabled).
-The ip address is used to forward all DNS queries to.
-.It \fBforward-to-port:\fR <port number>
-The port on which the remote server is running that answers forwarded queries.
-Default is 53.
.It \fBchroot:\fR <directory>
If given a chroot is done to the given directory. The default is none ("").
.It \fBusername:\fR <name>
Name of stub zone nameserver. Is itself resolved before it is used.
.It \fBstub-addr:\fR <IP address>
IP address of stub zone nameserver. Can be IP 4 or IP 6.
+To use a nondefault port for DNS communication append '@' with the port number.
.El
.Ss Forward Zone Options
Name of server to forward to. Is itself resolved before it is used.
.It \fBforward-addr:\fR <IP address>
IP address of server to forward to. Can be IP 4 or IP 6.
+To use a nondefault port for DNS communication append '@' with the port number.
.El
.Sh FILES
socklen_t addrlen;
for(p = s->addrs; p; p = p->next) {
log_assert(p->str);
- if(!ipstrtoaddr(p->str, UNBOUND_DNS_PORT, &addr, &addrlen)) {
+ if(!extstrtoaddr(p->str, &addr, &addrlen)) {
log_err("cannot parse forward %s ip address: '%s'",
s->name, p->str);
return 0;
return 0;
}
if(!delegpt_add_ns(dp, r, ldns_rdf_data(rdf)) ||
- !ipstrtoaddr(ip, UNBOUND_DNS_PORT, &addr, &addrlen) ||
+ !extstrtoaddr(ip, &addr, &addrlen) ||
!delegpt_add_target(dp, r, ldns_rdf_data(rdf), ldns_rdf_size(rdf),
&addr, addrlen)) {
ldns_rdf_deep_free(rdf);
socklen_t addrlen;
for(p = s->addrs; p; p = p->next) {
log_assert(p->str);
- if(!ipstrtoaddr(p->str, UNBOUND_DNS_PORT, &addr, &addrlen)) {
+ if(!extstrtoaddr(p->str, &addr, &addrlen)) {
log_err("cannot parse stub %s ip address: '%s'",
s->name, p->str);
return 0;
return 0;
}
iter_env->supports_ipv6 = cfg->do_ip6;
-
- /* forwarder address */
- if(cfg->fwd_address && cfg->fwd_address[0]) {
- if(!ipstrtoaddr(cfg->fwd_address, cfg->fwd_port,
- &iter_env->fwd_addr, &iter_env->fwd_addrlen)) {
- log_err("iterator: could not set forwarder address");
- return 0;
- }
- verbose(VERB_ALGO, "iterator: fwd queries to: %s %d",
- cfg->fwd_address, cfg->fwd_port);
- }
return 1;
}
return 1;
}
-/** new query for iterator in forward mode */
-static int
-fwd_new(struct module_qstate* qstate, int id)
-{
- struct iter_qstate* iq = (struct iter_qstate*)region_alloc(
- qstate->region, sizeof(struct iter_qstate));
- struct module_env* env = qstate->env;
- struct iter_env* ie = (struct iter_env*)env->modinfo[id];
- struct outbound_entry* e;
- uint16_t flags = 0; /* opcode=query, no flags */
- int dnssec = 1; /* always get dnssec info */
- qstate->minfo[id] = iq;
- if(!iq)
- return 0;
- memset(iq, 0, sizeof(*iq));
- outbound_list_init(&iq->outlist);
- e = (*env->send_query)(qstate->qinfo.qname, qstate->qinfo.qname_len,
- qstate->qinfo.qtype, qstate->qinfo.qclass, flags, dnssec,
- &ie->fwd_addr, ie->fwd_addrlen, qstate);
- if(!e)
- return 0;
- outbound_list_insert(&iq->outlist, e);
- qstate->ext_state[id] = module_wait_reply;
- return 1;
-}
-
-/** iterator handle reply from authoritative server */
-static int
-iter_handlereply(struct module_qstate* qstate, int id)
-{
- struct module_env* env = qstate->env;
- struct query_info reply_qinfo;
- struct reply_info* reply_msg;
- struct edns_data reply_edns;
- hashvalue_t h;
- int r;
- if((r=reply_info_parse(qstate->reply->c->buffer, env->alloc,
- &reply_qinfo, &reply_msg, qstate->env->scratch,
- &reply_edns))!=0)
- return 0;
-
- h = query_info_hash(&qstate->qinfo);
- (*qstate->env->query_done)(qstate, LDNS_RCODE_NOERROR, reply_msg);
- /* there should be no dependencies in this forwarding mode */
- (*qstate->env->walk_supers)(qstate, id, NULL);
- dns_cache_store_msg(qstate->env, &reply_qinfo, h, reply_msg);
- qstate->ext_state[id] = module_finished;
- return 1;
-}
-
-/** perform forwarder functionality */
-static void
-perform_forward(struct module_qstate* qstate, enum module_ev event, int id,
- struct outbound_entry* outbound)
-{
- verbose(VERB_ALGO, "iterator: forwarding");
- if(event == module_event_new) {
- if(!fwd_new(qstate, id)) {
- (*qstate->env->query_done)(qstate,
- LDNS_RCODE_SERVFAIL, NULL);
- (*qstate->env->walk_supers)(qstate, id, NULL);
- qstate->ext_state[id] = module_error;
- return;
- }
- return;
- }
- /* it must be a query reply */
- if(!outbound) {
- verbose(VERB_ALGO, "query reply was not serviced");
- (*qstate->env->query_done)(qstate, LDNS_RCODE_SERVFAIL, NULL);
- (*qstate->env->walk_supers)(qstate, id, NULL);
- qstate->ext_state[id] = module_error;
- return;
- }
- if(event == module_event_timeout || event == module_event_error) {
- (*qstate->env->query_done)(qstate, LDNS_RCODE_SERVFAIL, NULL);
- (*qstate->env->walk_supers)(qstate, id, NULL);
- qstate->ext_state[id] = module_error;
- return;
- }
- if(event == module_event_reply) {
- if(!iter_handlereply(qstate, id)) {
- (*qstate->env->query_done)(qstate,
- LDNS_RCODE_SERVFAIL, NULL);
- (*qstate->env->walk_supers)(qstate, id, NULL);
- qstate->ext_state[id] = module_error;
- }
- return;
- }
- log_err("bad event for iterator[forwarding]");
- (*qstate->env->query_done)(qstate, LDNS_RCODE_SERVFAIL, NULL);
- (*qstate->env->walk_supers)(qstate, id, NULL);
- qstate->ext_state[id] = module_error;
-}
-
/**
* Transition to the next state. This can be used to advance a currently
* processing event. It cannot be used to reactivate a forEvent.
log_query_info(VERB_DETAIL, "iterator operate: chased to",
&iq->qchase);
- if(ie->fwd_addrlen != 0) {
- perform_forward(qstate, event, id, outbound);
- return;
- }
/* perform iterator state machine */
if(event == module_event_new && iq == NULL) {
if(!iter_new(qstate, id)) {
* Global state for the iterator.
*/
struct iter_env {
- /** address to forward to */
- struct sockaddr_storage fwd_addr;
- /** length of fwd_addr, if not 0, forward mode is used */
- socklen_t fwd_addrlen;
-
/**
* The hints -- these aren't stored in the cache because they don't
* expire. The hints are always used to "prime" the cache. Note
; This is a comment.
; config options go here.
-server: forward-to: "127.0.0.1"
+forward-zone: name: "." forward-addr: 127.0.0.1
CONFIG_END
SCENARIO_BEGIN Sample of a valid query
; This is a comment.
; config options go here.
-server: forward-to: "127.0.0.1"
+forward-zone: name: "." forward-addr: 127.0.0.1
CONFIG_END
SCENARIO_BEGIN Query receives answer from the cache
; config options go here.
-server: forward-to: "127.0.0.1"
+forward-zone: name: "." forward-addr: 127.0.0.1
CONFIG_END
SCENARIO_BEGIN Forwarder and an error happens on server query.
STEP 1 QUERY
server:
msg-cache-size: 1 # one whole byte!
msg-cache-slabs: 1
- forward-to: "127.0.0.1"
+forward-zone: name: "." forward-addr: 127.0.0.1
CONFIG_END
SCENARIO_BEGIN Old answer is dropped from the cache
; here config file options:
server:
msg-cache-size: 1024
- forward-to: "127.0.0.1"
+forward-zone:
+ name: "."
+ forward-addr: 127.0.0.1
CONFIG_END
SCENARIO_BEGIN Query receives answer not from the cache
; config options go here.
-server: forward-to: "127.0.0.1"
+forward-zone: name: "." forward-addr: 127.0.0.1
CONFIG_END
SCENARIO_BEGIN Forwarder and a timeout happens on server query.
STEP 1 QUERY
; config options go here.
server:
num-queries-per-thread: 1
- forward-to: "127.0.0.1"
+forward-zone:
+ name: "."
+ forward-addr: 127.0.0.1
CONFIG_END
SCENARIO_BEGIN Sample of a valid query
; This is a comment.
; config options go here.
-server: forward-to: "127.0.0.1"
+forward-zone: name: "." forward-addr: 127.0.0.1
CONFIG_END
SCENARIO_BEGIN RRset TTL is updated from message.
; This is a comment.
; config options go here.
-server: forward-to: "127.0.0.1"
+forward-zone: name: "." forward-addr: 127.0.0.1
CONFIG_END
SCENARIO_BEGIN Untrusted rrset not used for update
SECTION ADDITIONAL
example.com. IN NS ns.eeeek.com.
example.com. IN NS ns2.eeeek.com.
- ns.eeeek.com. IN A 55.44.33.22
- ns2.eeeek.com. IN A 55.44.33.24
ENTRY_END
; This is a comment.
; config options go here.
-server: forward-to: "127.0.0.1"
+forward-zone: name: "." forward-addr: 127.0.0.1
CONFIG_END
SCENARIO_BEGIN RRset is updated from other message that passes by.
cfg->infra_cache_slabs = 4;
cfg->infra_cache_numhosts = 1000;
cfg->infra_cache_numlame = 1000;
- if(!(cfg->fwd_address = strdup(""))) goto error_exit;
if(!(cfg->username = strdup(""))) goto error_exit;
if(!(cfg->chrootdir = strdup(""))) goto error_exit;
if(!(cfg->directory = strdup("/etc/unbound"))) goto error_exit;
if(!(cfg->logfile = strdup(""))) goto error_exit;
if(!(cfg->pidfile = strdup("unbound.pid"))) goto error_exit;
if(!(cfg->target_fetch_policy = strdup("3 2 1 0 0"))) goto error_exit;
- cfg->fwd_port = UNBOUND_DNS_PORT;
cfg->do_daemonize = 1;
cfg->num_ifs = 0;
cfg->ifs = NULL;
config_delete(struct config_file* cfg)
{
if(!cfg) return;
- free(cfg->fwd_address);
free(cfg->username);
free(cfg->chrootdir);
free(cfg->directory);
/** max number of lame zones per host in the infra cache */
size_t infra_cache_numlame;
- /** forwarder address. string. If not NULL fwder mode is enabled. */
- char* fwd_address;
- /** forwarder port */
- int fwd_port;
-
/** the target fetch policy for the iterator */
char* target_fetch_policy;
/** the stub definitions, linked list */
struct config_stub* stubs;
- /** the forward definitions, linked list */
+ /** the forward zone definitions, linked list */
struct config_stub* forwards;
/** harden against very small edns buffer sizes */
do-ip6{COLON} { YDOUT; return VAR_DO_IP6;}
do-udp{COLON} { YDOUT; return VAR_DO_UDP;}
do-tcp{COLON} { YDOUT; return VAR_DO_TCP;}
-forward-to{COLON} { YDOUT; return VAR_FORWARD_TO;}
-forward-to-port{COLON} { YDOUT; return VAR_FORWARD_TO_PORT;}
interface{COLON} { YDOUT; return VAR_INTERFACE;}
chroot{COLON} { YDOUT; return VAR_CHROOT;}
username{COLON} { YDOUT; return VAR_USERNAME;}
%token <str> STRING
%token VAR_SERVER VAR_VERBOSITY VAR_NUM_THREADS VAR_PORT
%token VAR_OUTGOING_PORT VAR_OUTGOING_RANGE VAR_INTERFACE
-%token VAR_DO_IP4 VAR_DO_IP6 VAR_DO_UDP VAR_DO_TCP
-%token VAR_FORWARD_TO VAR_FORWARD_TO_PORT VAR_CHROOT
-%token VAR_USERNAME VAR_DIRECTORY VAR_LOGFILE VAR_PIDFILE
+%token VAR_DO_IP4 VAR_DO_IP6 VAR_DO_UDP VAR_DO_TCP
+%token VAR_CHROOT VAR_USERNAME VAR_DIRECTORY VAR_LOGFILE VAR_PIDFILE
%token VAR_MSG_CACHE_SIZE VAR_MSG_CACHE_SLABS VAR_NUM_QUERIES_PER_THREAD
%token VAR_RRSET_CACHE_SIZE VAR_RRSET_CACHE_SLABS VAR_OUTGOING_NUM_TCP
%token VAR_INFRA_HOST_TTL VAR_INFRA_LAME_TTL VAR_INFRA_CACHE_SLABS
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
-toplevelvar: serverstart contents_server ;
+toplevelvar: serverstart contents_server | stubstart contents_stub |
+ forwardstart contents_forward
+ ;
/* server: declaration */
serverstart: VAR_SERVER
| ;
content_server: server_num_threads | server_verbosity | server_port |
server_outgoing_port | server_outgoing_range | server_do_ip4 |
- server_do_ip6 | server_do_udp | server_do_tcp | server_forward_to |
- server_forward_to_port | server_interface | server_chroot |
- server_username | server_directory | server_logfile | server_pidfile |
+ server_do_ip6 | server_do_udp | server_do_tcp |
+ server_interface | server_chroot | server_username |
+ server_directory | server_logfile | server_pidfile |
server_msg_cache_size | server_msg_cache_slabs |
server_num_queries_per_thread | server_rrset_cache_size |
server_rrset_cache_slabs | server_outgoing_num_tcp |
server_infra_host_ttl | server_infra_lame_ttl |
server_infra_cache_slabs | server_infra_cache_numhosts |
- server_infra_cache_numlame | stubstart contents_stub |
- server_target_fetch_policy | server_harden_short_bufsize |
- server_harden_large_queries | forwardstart contents_forward
+ server_infra_cache_numlame | server_target_fetch_policy |
+ server_harden_short_bufsize | server_harden_large_queries
;
stubstart: VAR_STUB_ZONE
{
free($2);
}
;
-server_forward_to: VAR_FORWARD_TO STRING
- {
- OUTYY(("P(server_forward_to:%s)\n", $2));
- free(cfg_parser->cfg->fwd_address);
- cfg_parser->cfg->fwd_address = $2;
- }
- ;
-server_forward_to_port: VAR_FORWARD_TO_PORT STRING
- {
- OUTYY(("P(server_forward_to_port:%s)\n", $2));
- if(atoi($2) == 0)
- yyerror("number expected");
- else cfg_parser->cfg->fwd_port = atoi($2);
- free($2);
- }
- ;
server_chroot: VAR_CHROOT STRING
{
OUTYY(("P(server_chroot:%s)\n", $2));
#include "util/data/dname.h"
#include <fcntl.h>
+/** max length of an IP address (the address portion) that we allow */
+#define MAX_ADDR_STRLEN 128 /* characters */
+
/** returns true is string addr is an ip6 specced address */
int
str_is_ip6(const char* str)
str, family, dest, (int)port, (int)addrlen);
}
+int
+extstrtoaddr(const char* str, struct sockaddr_storage* addr,
+ socklen_t* addrlen)
+{
+ char* s;
+ int port = UNBOUND_DNS_PORT;
+ if((s=strchr(str, '@'))) {
+ char buf[MAX_ADDR_STRLEN];
+ if(s-str >= MAX_ADDR_STRLEN) {
+ log_err("address too long: '%s'", str);
+ return 0;
+ }
+ strncpy(buf, str, MAX_ADDR_STRLEN);
+ buf[s-str] = 0;
+ port = atoi(s+1);
+ if(port == 0 && strcmp(s+1,"0")!=0) {
+ log_err("bad port spec in address: '%s", str);
+ return 0;
+ }
+ return ipstrtoaddr(buf, port, addr, addrlen);
+ }
+ return ipstrtoaddr(str, port, addr, addrlen);
+}
+
+
int
ipstrtoaddr(const char* ip, int port, struct sockaddr_storage* addr,
socklen_t* addrlen)
void log_name_addr(enum verbosity_value v, const char* str, uint8_t* zone,
struct sockaddr_storage* addr, socklen_t addrlen);
+/**
+ * Convert address string, with @port appendix, to sockaddr.
+ * Uses DNS port by default.
+ * @param str: the string
+ * @param addr: where to store sockaddr.
+ * @param addrlen: length of stored sockaddr is returned.
+ * @return 0 on error.
+ */
+int extstrtoaddr(const char* str, struct sockaddr_storage* addr,
+ socklen_t* addrlen);
+
/**
* Convert ip address string and port to sockaddr.
* @param ip: ip4 or ip6 address string.