+18 July 2007: Wouter
+ - do not query addresses, 127.0.0.1, and ::1 by default.
+
17 July 2007: Wouter
- forward zone options in config file.
- forward per zone in iterator. takes precendence over stubs.
o fallback without EDNS if result is NOTIMPL, now only on FORMERR like in java.
o scrubber has slow pkt_subdomain and pkt_strict_subdomain functions.
o get serverselection algorithm out of local optimum.
+o donotqueryaddresses allow specification of subnets, use trie to store.
# target-fetch-policy: "3 2 1 0 0"
# Harden against very small EDNS buffer sizes.
- # harden_short_bufsize: no
+ # harden-short-bufsize: no
# Harden against unseemly large queries.
- # harden_large_queries: no
+ # harden-large-queries: no
+
+ # Do not query the following addresses. No DNS queries are sent there.
+ # List one address per entry. To block other ports than the default
+ # 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
# Stub zones.
# Create entries like below, to make all queries for 'example.com' and
Very large queries are ignored. Default is off, since it is legal protocol
wise to send these, and could be necessary for operation if TSIG or EDNS
payload is very large.
+.It \fBdo-not-query-address:\fR <IP address>
+Do not query the given IP address. Can be IP4 or IP6. By default the
+DNS port is blocked for that address. Appending "@portnumber" will block
+other port numbers.
.El
.Ss Stub Zone Options
--- /dev/null
+/*
+ * iterator/iter_donotq.c - iterative resolver donotqueryaddresses storage.
+ *
+ * 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 functions to assist the iterator module.
+ * The donotqueryaddresses are stored and looked up. These addresses
+ * (like 127.0.0.1) must not be used to send queries to, and can be
+ * discarded immediately from the server selection.
+ */
+#include "config.h"
+#include "iterator/iter_donotq.h"
+#include "util/region-allocator.h"
+#include "util/log.h"
+#include "util/config_file.h"
+#include "util/net_help.h"
+
+/** compare two donotq entries */
+static int
+donotq_cmp(const void* k1, const void* k2)
+{
+ struct iter_donotq_addr* n1 = (struct iter_donotq_addr*)k1;
+ struct iter_donotq_addr* n2 = (struct iter_donotq_addr*)k2;
+ return sockaddr_cmp(&n1->addr, n1->addrlen, &n2->addr, n2->addrlen);
+}
+
+struct iter_donotq*
+donotq_create()
+{
+ struct iter_donotq* dq = (struct iter_donotq*)calloc(1,
+ sizeof(struct iter_donotq));
+ if(!dq)
+ return NULL;
+ dq->region = region_create(malloc, free);
+ if(!dq->region) {
+ donotq_delete(dq);
+ return NULL;
+ }
+ return dq;
+}
+
+void
+donotq_delete(struct iter_donotq* dq)
+{
+ if(!dq)
+ return;
+ region_destroy(dq->region);
+ free(dq->tree);
+ free(dq);
+}
+
+/** insert new address into donotq structure */
+static int
+donotq_insert(struct iter_donotq* dq, struct sockaddr_storage* addr,
+ socklen_t addrlen)
+{
+ struct iter_donotq_addr* node = region_alloc(dq->region,
+ sizeof(struct iter_donotq_addr));
+ if(!node)
+ return 0;
+ node->node.key = node;
+ memcpy(&node->addr, addr, addrlen);
+ node->addrlen = addrlen;
+ if(!rbtree_insert(dq->tree, &node->node)) {
+ log_warn("duplicate donotquery address ignored.");
+ }
+ return 1;
+}
+
+/** read donotq config */
+static int
+read_donotq(struct iter_donotq* dq, struct config_file* cfg)
+{
+ struct config_strlist* p;
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ for(p = cfg->donotqueryaddrs; p; p = p->next) {
+ log_assert(p->str);
+ if(!extstrtoaddr(p->str, &addr, &addrlen)) {
+ log_err("cannot parse donotquery ip address: '%s'",
+ p->str);
+ return 0;
+ }
+ if(!donotq_insert(dq, &addr, addrlen)) {
+ log_err("out of memory");
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int
+donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg)
+{
+ free(dq->tree);
+ dq->tree = rbtree_create(donotq_cmp);
+ if(!dq->tree)
+ return 0;
+ if(!read_donotq(dq, cfg))
+ return 0;
+ return 1;
+}
+
+int
+donotq_lookup(struct iter_donotq* donotq, struct sockaddr_storage* addr,
+ socklen_t addrlen)
+{
+ /* lookup in the tree */
+ struct iter_donotq_addr key;
+ key.node.key = &key;
+ memcpy(&key.addr, addr, addrlen);
+ key.addrlen = addrlen;
+ if(rbtree_search(donotq->tree, &key))
+ return 1;
+ return 0;
+}
--- /dev/null
+/*
+ * iterator/iter_donotq.h - iterative resolver donotqueryaddresses storage.
+ *
+ * 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 functions to assist the iterator module.
+ * Keep track of the donotquery addresses and lookup fast.
+ */
+
+#ifndef ITERATOR_ITER_DONOTQ_H
+#define ITERATOR_ITER_DONOTQ_H
+#include "util/rbtree.h"
+struct iter_env;
+struct config_file;
+struct region;
+
+/**
+ * Iterator donotqueryaddresses structure
+ */
+struct iter_donotq {
+ /** region for allocation */
+ struct region* region;
+ /**
+ * Tree of the single addresses that are blocked.
+ * contents of type iter_donotq_addr.
+ */
+ rbtree_t* tree;
+};
+
+/**
+ * Iterator donotquery address.
+ * A single address that must not be used to send queries to.
+ */
+struct iter_donotq_addr {
+ /** redblacktree node, key is this structure: addr and addrlen */
+ rbnode_t node;
+ /** address */
+ struct sockaddr_storage addr;
+ /** length of addr */
+ socklen_t addrlen;
+};
+
+/**
+ * Create donotqueryaddresses structure
+ * @return new structure or NULL on error.
+ */
+struct iter_donotq* donotq_create();
+
+/**
+ * Delete donotqueryaddresses structure.
+ * @param donotq: to delete.
+ */
+void donotq_delete(struct iter_donotq* donotq);
+
+/**
+ * Process donotqueryaddresses config.
+ * @param donotq: where to store.
+ * @param cfg: config options.
+ * @return 0 on error.
+ */
+int donotq_apply_cfg(struct iter_donotq* donotq, struct config_file* cfg);
+
+/**
+ * See if an address is blocked.
+ * @param donotq: structure for address storage.
+ * @param addr: address to check
+ * @param addrlen: length of addr.
+ * @return: true if the address must not be queried. false if unlisted.
+ */
+int donotq_lookup(struct iter_donotq* donotq, struct sockaddr_storage* addr,
+ socklen_t addrlen);
+
+#endif /* ITERATOR_ITER_DONOTQ_H */
int forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg);
/**
- * Find a forward zone information
+ * Find forward zone information
* For this qname/qclass find forward zone information, returns delegation
* point with server names and addresses, or NULL if no forwarding is needed.
*
#include "iterator/iterator.h"
#include "iterator/iter_hints.h"
#include "iterator/iter_fwd.h"
+#include "iterator/iter_donotq.h"
#include "iterator/iter_delegpt.h"
#include "services/cache/infra.h"
#include "services/cache/dns.h"
log_err("Could not set forward zones");
return 0;
}
+ if(!iter_env->donotq)
+ iter_env->donotq = donotq_create();
+ if(!iter_env->donotq || !donotq_apply_cfg(iter_env->donotq, cfg)) {
+ log_err("Could not set donotqueryaddresses");
+ return 0;
+ }
iter_env->supports_ipv6 = cfg->do_ip6;
return 1;
}
{
int rtt;
int lame;
- /* TODO: check ie->donotqueryaddrs for a */
+ if(donotq_lookup(iter_env->donotq, &a->addr, a->addrlen)) {
+ return -1; /* server is on the donotquery list */
+ }
if(!iter_env->supports_ipv6 && addr_is_ip6(&a->addr)) {
- return -1;
+ return -1; /* there is no ip6 available */
}
/* check lameness - need zone , class info */
if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen,
#include "iterator/iter_utils.h"
#include "iterator/iter_hints.h"
#include "iterator/iter_fwd.h"
+#include "iterator/iter_donotq.h"
#include "iterator/iter_delegpt.h"
#include "iterator/iter_resptype.h"
#include "iterator/iter_scrub.h"
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);
}
struct delegpt;
struct iter_hints;
struct iter_forwards;
+struct iter_donotq;
struct iter_prep_list;
/** max number of query restarts. Determines max number of CNAME chain. */
struct iter_forwards* fwds;
/** A set of inetaddrs that should never be queried. */
- /* struct bla donotquery_addrs TODO */
+ struct iter_donotq* donotq;
/** The maximum dependency depth that this resolver will pursue. */
int max_dependency_depth;
{
struct infra_host_key* k1 = (struct infra_host_key*)key1;
struct infra_host_key* k2 = (struct infra_host_key*)key2;
- if(k1->addrlen != k2->addrlen) {
- if(k1->addrlen < k2->addrlen)
- return -1;
- return 1;
- }
- return memcmp(&k1->addr, &k2->addr, k1->addrlen);
+ return sockaddr_cmp(&k1->addr, k1->addrlen, &k2->addr, k2->addrlen);
}
/** delete key, and destroy the lock */
static void serviced_tcp_initiate(struct outside_network* outnet,
struct serviced_query* sq, ldns_buffer* buff);
-/** compare sockaddr */
-static int
-sockaddr_cmp(struct sockaddr_storage* addr1, socklen_t len1,
- struct sockaddr_storage* addr2, socklen_t len2)
-{
- struct sockaddr_in* p1_in = (struct sockaddr_in*)addr1;
- struct sockaddr_in* p2_in = (struct sockaddr_in*)addr2;
- struct sockaddr_in6* p1_in6 = (struct sockaddr_in6*)addr1;
- struct sockaddr_in6* p2_in6 = (struct sockaddr_in6*)addr2;
- if(len1 < len2)
- return -1;
- if(len1 > len2)
- return 1;
- log_assert(len1 == len2);
- if( p1_in->sin_family < p2_in->sin_family)
- return -1;
- if( p1_in->sin_family > p2_in->sin_family)
- return 1;
- log_assert( p1_in->sin_family == p2_in->sin_family );
- /* compare ip4 */
- if( p1_in->sin_family == AF_INET ) {
- /* just order it, ntohs not required */
- if(p1_in->sin_port < p2_in->sin_port)
- return -1;
- if(p1_in->sin_port > p2_in->sin_port)
- return 1;
- log_assert(p1_in->sin_port == p2_in->sin_port);
- return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE);
- } else if (p1_in6->sin6_family == AF_INET6) {
- /* just order it, ntohs not required */
- if(p1_in6->sin6_port < p2_in6->sin6_port)
- return -1;
- if(p1_in6->sin6_port > p2_in6->sin6_port)
- return 1;
- log_assert(p1_in6->sin6_port == p2_in6->sin6_port);
- return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr,
- INET6_SIZE);
- } else {
- /* eek unknown type, perform this comparison for sanity. */
- return memcmp(addr1, addr2, len1);
- }
-}
-
/** compare function of pending rbtree */
static int
pending_cmp(const void* key1, const void* key2)
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->donotqueryaddrs = NULL;
+ if(!cfg_strlist_insert(&cfg->donotqueryaddrs, strdup("127.0.0.1")))
+ goto error_exit;
+ if(!cfg_strlist_insert(&cfg->donotqueryaddrs, strdup("::1")))
+ goto error_exit;
cfg->do_daemonize = 1;
cfg->num_ifs = 0;
cfg->ifs = NULL;
}
config_delstubs(cfg->stubs);
config_delstubs(cfg->forwards);
+ config_delstrlist(cfg->donotqueryaddrs);
free(cfg);
}
return 1;
}
+int
+cfg_strlist_insert(struct config_strlist** head, char* item)
+{
+ struct config_strlist *s;
+ if(!item || !head)
+ return 0;
+ s = (struct config_strlist*)calloc(1, sizeof(struct config_strlist));
+ if(!s)
+ return 0;
+ s->str = item;
+ s->next = *head;
+ *head = s;
+ return 1;
+}
struct config_stub* stubs;
/** the forward zone definitions, linked list */
struct config_stub* forwards;
+ /** list of donotquery addresses, linked list */
+ struct config_strlist* donotqueryaddrs;
/** harden against very small edns buffer sizes */
int harden_short_bufsize;
*/
void config_delete(struct config_file* config);
+/**
+ * Insert string into strlist.
+ * @param head: pointer to strlist head variable.
+ * @param item: new item. malloced by caller. If NULL the insertion fails.
+ * @return: true on success.
+ */
+int cfg_strlist_insert(struct config_strlist** head, char* item);
+
/**
* Used during options parsing
*/
forward-zone{COLON} { YDOUT; return VAR_FORWARD_ZONE;}
forward-addr{COLON} { YDOUT; return VAR_FORWARD_ADDR;}
forward-host{COLON} { YDOUT; return VAR_FORWARD_HOST;}
+do-not-query-address{COLON} { YDOUT; return VAR_DO_NOT_QUERY_ADDRESS;}
{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;}
/* Quoted strings. Strip leading and ending quotes */
%token VAR_STUB_ZONE VAR_STUB_HOST VAR_STUB_ADDR VAR_TARGET_FETCH_POLICY
%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
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
server_infra_host_ttl | server_infra_lame_ttl |
server_infra_cache_slabs | server_infra_cache_numhosts |
server_infra_cache_numlame | server_target_fetch_policy |
- server_harden_short_bufsize | server_harden_large_queries
+ server_harden_short_bufsize | server_harden_large_queries |
+ server_do_not_query_address
;
stubstart: VAR_STUB_ZONE
{
free($2);
}
;
+server_do_not_query_address: VAR_DO_NOT_QUERY_ADDRESS STRING
+ {
+ OUTYY(("P(server_do_not_query_address:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->donotqueryaddrs, $2))
+ yyerror("out of memory");
+ }
+ ;
stub_name: VAR_NAME STRING
{
OUTYY(("P(name:%s)\n", $2));
;
stub_host: VAR_STUB_HOST STRING
{
- struct config_strlist *s = (struct config_strlist*)calloc(1,
- sizeof(struct config_strlist));
OUTYY(("P(stub-host:%s)\n", $2));
- if(s) {
- s->str = $2;
- s->next = cfg_parser->cfg->stubs->hosts;
- cfg_parser->cfg->stubs->hosts = s;
- } else
+ if(!cfg_strlist_insert(&cfg_parser->cfg->stubs->hosts, $2))
yyerror("out of memory");
}
;
stub_addr: VAR_STUB_ADDR STRING
{
- struct config_strlist *s = (struct config_strlist*)calloc(1,
- sizeof(struct config_strlist));
OUTYY(("P(stub-addr:%s)\n", $2));
- if(s) {
- s->str = $2;
- s->next = cfg_parser->cfg->stubs->addrs;
- cfg_parser->cfg->stubs->addrs = s;
- } else
+ if(!cfg_strlist_insert(&cfg_parser->cfg->stubs->addrs, $2))
yyerror("out of memory");
}
;
;
forward_host: VAR_FORWARD_HOST STRING
{
- struct config_strlist *s = (struct config_strlist*)calloc(1,
- sizeof(struct config_strlist));
OUTYY(("P(forward-host:%s)\n", $2));
- if(s) {
- s->str = $2;
- s->next = cfg_parser->cfg->forwards->hosts;
- cfg_parser->cfg->forwards->hosts = s;
- } else
+ if(!cfg_strlist_insert(&cfg_parser->cfg->forwards->hosts, $2))
yyerror("out of memory");
}
;
forward_addr: VAR_FORWARD_ADDR STRING
{
- struct config_strlist *s = (struct config_strlist*)calloc(1,
- sizeof(struct config_strlist));
OUTYY(("P(forward-addr:%s)\n", $2));
- if(s) {
- s->str = $2;
- s->next = cfg_parser->cfg->forwards->addrs;
- cfg_parser->cfg->forwards->addrs = s;
- } else
+ if(!cfg_strlist_insert(&cfg_parser->cfg->forwards->addrs, $2))
yyerror("out of memory");
}
;
str, namebuf, family, dest, (int)port);
}
+int
+sockaddr_cmp(struct sockaddr_storage* addr1, socklen_t len1,
+ struct sockaddr_storage* addr2, socklen_t len2)
+{
+ struct sockaddr_in* p1_in = (struct sockaddr_in*)addr1;
+ struct sockaddr_in* p2_in = (struct sockaddr_in*)addr2;
+ struct sockaddr_in6* p1_in6 = (struct sockaddr_in6*)addr1;
+ struct sockaddr_in6* p2_in6 = (struct sockaddr_in6*)addr2;
+ if(len1 < len2)
+ return -1;
+ if(len1 > len2)
+ return 1;
+ log_assert(len1 == len2);
+ if( p1_in->sin_family < p2_in->sin_family)
+ return -1;
+ if( p1_in->sin_family > p2_in->sin_family)
+ return 1;
+ log_assert( p1_in->sin_family == p2_in->sin_family );
+ /* compare ip4 */
+ if( p1_in->sin_family == AF_INET ) {
+ /* just order it, ntohs not required */
+ if(p1_in->sin_port < p2_in->sin_port)
+ return -1;
+ if(p1_in->sin_port > p2_in->sin_port)
+ return 1;
+ log_assert(p1_in->sin_port == p2_in->sin_port);
+ return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE);
+ } else if (p1_in6->sin6_family == AF_INET6) {
+ /* just order it, ntohs not required */
+ if(p1_in6->sin6_port < p2_in6->sin6_port)
+ return -1;
+ if(p1_in6->sin6_port > p2_in6->sin6_port)
+ return 1;
+ log_assert(p1_in6->sin6_port == p2_in6->sin6_port);
+ return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr,
+ INET6_SIZE);
+ } else {
+ /* eek unknown type, perform this comparison for sanity. */
+ return memcmp(addr1, addr2, len1);
+ }
+}
+
int
addr_is_ip6(struct sockaddr_storage* addr)
{
void log_nametypeclass(enum verbosity_value v, const char* str,
uint8_t* name, uint16_t type, uint16_t dclass);
+/**
+ * Compare two sockaddrs. Imposes an ordering on the addresses.
+ * @param addr1: address 1.
+ * @param len1: lengths of addr1.
+ * @param addr2: address 2.
+ * @param len2: lengths of addr2.
+ * @return: 0 if addr1 == addr2. -1 if addr1 is smaller, +1 if larger.
+ */
+int sockaddr_cmp(struct sockaddr_storage* addr1, socklen_t len1,
+ struct sockaddr_storage* addr2, socklen_t len2);
+
/**
* Checkout address family.
* @param addr: the sockaddr to examine.