From: Wouter Wijngaards Date: Fri, 19 Oct 2007 18:09:11 +0000 (+0000) Subject: Donotquery for netblocks. X-Git-Tag: release-0.6~35 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=288521038443f45a5b0b0bd2a5d3e7affea1988b;p=thirdparty%2Funbound.git Donotquery for netblocks. git-svn-id: file:///svn/unbound/trunk@709 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/example.conf b/doc/example.conf index 08072b329..c5b0c2344 100644 --- a/doc/example.conf +++ b/doc/example.conf @@ -166,9 +166,8 @@ server: # harden-glue: yes # 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 + # List one address per entry. List classless netblocks with /size, + # do-not-query-address: 127.0.0.1/8 # do-not-query-address: ::1 # module configuration of the server. A string with identifiers diff --git a/iterator/iter_donotq.c b/iterator/iter_donotq.c index 3bf4522c8..ce6d52e78 100644 --- a/iterator/iter_donotq.c +++ b/iterator/iter_donotq.c @@ -53,7 +53,13 @@ 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); + int r = sockaddr_cmp(&n1->addr, n1->addrlen, &n2->addr, n2->addrlen); + if(r != 0) return r; + if(n1->net < n2->net) + return -1; + if(n1->net > n2->net) + return 1; + return 0; } struct iter_donotq* @@ -84,7 +90,7 @@ donotq_delete(struct iter_donotq* dq) /** insert new address into donotq structure */ static int donotq_insert(struct iter_donotq* dq, struct sockaddr_storage* addr, - socklen_t addrlen) + socklen_t addrlen, int net) { struct iter_donotq_addr* node = regional_alloc(dq->region, sizeof(struct iter_donotq_addr)); @@ -93,27 +99,72 @@ donotq_insert(struct iter_donotq* dq, struct sockaddr_storage* addr, node->node.key = node; memcpy(&node->addr, addr, addrlen); node->addrlen = addrlen; + node->net = net; + node->parent = NULL; if(!rbtree_insert(dq->tree, &node->node)) { verbose(VERB_DETAIL, "duplicate donotquery address ignored."); } return 1; } +/** make sure the netblock ends in zeroes for compare in tree */ +static void +mask_block(int ip6, struct sockaddr_storage* addr, int net) +{ + uint8_t mask[8] = {0x0, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}; + int i, max; + uint8_t* s; + if(ip6) { + s = (uint8_t*)&((struct sockaddr_in6*)addr)->sin6_addr; + max = 128; + } else { + s = (uint8_t*)&((struct sockaddr_in*)addr)->sin_addr; + max = 32; + } + if(net >= max) + return; + for(i=net/8+1; idonotqueryaddrs; p; p = p->next) { log_assert(p->str); - if(!extstrtoaddr(p->str, &addr, &addrlen)) { + net = (str_is_ip6(p->str)?128:32); + if((s=strchr(p->str, '/'))) { + if(atoi(s+1) > net) { + log_err("netblock too large: %s", p->str); + return 0; + } + net = atoi(s+1); + if(net == 0 && strcmp(s+1, "0") != 0) { + log_err("cannot parse donotquery netblock:" + " '%s'", p->str); + return 0; + } + *s = '\0'; + } + if(!ipstrtoaddr(p->str, UNBOUND_DNS_PORT, &addr, &addrlen)) { + if(s) *s = '/'; log_err("cannot parse donotquery ip address: '%s'", p->str); return 0; } - if(!donotq_insert(dq, &addr, addrlen)) { + if(s) { + *s = '/'; + mask_block(str_is_ip6(p->str), &addr, net); + } + if(!donotq_insert(dq, &addr, addrlen, net)) { log_err("out of memory"); return 0; } @@ -121,6 +172,70 @@ read_donotq(struct iter_donotq* dq, struct config_file* cfg) return 1; } +/** number of bits that two addrs share (are equal) */ +static int +addr_in_common(struct sockaddr_storage* addr1, int net1, + struct sockaddr_storage* addr2, int net2, socklen_t addrlen) +{ + int min = (net1sin6_addr; + s2 = (uint8_t*)&((struct sockaddr_in6*)addr2)->sin6_addr; + to = 16; + } else { + s1 = (uint8_t*)&((struct sockaddr_in*)addr1)->sin_addr; + s2 = (uint8_t*)&((struct sockaddr_in*)addr2)->sin_addr; + to = 4; + } + /* match = bits_in_common(s1, s2, to); */ + for(i=0; i min) match = min; + return match; +} + +/** initialise parent pointers in the tree */ +static void +donotq_init_parents(struct iter_donotq* donotq) +{ + struct iter_donotq_addr* node, *prev = NULL, *p; + int m; + RBTREE_FOR(node, struct iter_donotq_addr*, donotq->tree) { + node->parent = NULL; + if(!prev || prev->addrlen != node->addrlen) { + prev = node; + continue; + } + m = addr_in_common(&prev->addr, prev->net, &node->addr, + node->net, node->addrlen); + /* sort order like: ::/0, 1::/2, 1::/4, ... 2::/2 */ + /* find the previous, or parent-parent-parent */ + for(p = prev; p; p = p->parent) + if(p->net <= m) { + /* ==: since prev matched m, this is closest*/ + /* <: prev matches more, but is not a parent, + * this one is a (grand)parent */ + node->parent = p; + break; + } + prev = node; + } +} + int donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg) { @@ -130,6 +245,7 @@ donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg) return 0; if(!read_donotq(dq, cfg)) return 0; + donotq_init_parents(dq); return 1; } @@ -138,12 +254,31 @@ donotq_lookup(struct iter_donotq* donotq, struct sockaddr_storage* addr, socklen_t addrlen) { /* lookup in the tree */ + rbnode_t* res = NULL; + struct iter_donotq_addr* result; struct iter_donotq_addr key; key.node.key = &key; memcpy(&key.addr, addr, addrlen); key.addrlen = addrlen; - if(rbtree_search(donotq->tree, &key)) + key.net = (addr_is_ip6(addr, addrlen)?128:32); + if(rbtree_find_less_equal(donotq->tree, &key, &res)) { + /* exact */ return 1; + } else { + /* smaller element (or no element) */ + int m; + result = (struct iter_donotq_addr*)res; + if(!result || result->addrlen != addrlen) + return 0; + /* count number of bits matched */ + m = addr_in_common(&result->addr, result->net, addr, + key.net, addrlen); + while(result) { /* go up until addr is inside netblock */ + if(result->net <= m) + return 1; + result = result->parent; + } + } return 0; } diff --git a/iterator/iter_donotq.h b/iterator/iter_donotq.h index d86e3535d..bb6d659e0 100644 --- a/iterator/iter_donotq.h +++ b/iterator/iter_donotq.h @@ -71,6 +71,10 @@ struct iter_donotq_addr { struct sockaddr_storage addr; /** length of addr */ socklen_t addrlen; + /** netblock size */ + int net; + /** parent node in donotq tree that encompasses this entry */ + struct iter_donotq_addr* parent; }; /** diff --git a/util/config_file.c b/util/config_file.c index 1ff08aad6..8b44e11fc 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -99,7 +99,7 @@ config_create() 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"))) + if(!cfg_strlist_insert(&cfg->donotqueryaddrs, strdup("127.0.0.0/8"))) goto error_exit; if(!cfg_strlist_insert(&cfg->donotqueryaddrs, strdup("::1"))) goto error_exit;