private address and private domain config option read and store.

git-svn-id: file:///svn/unbound/trunk@1223 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2008-09-03 14:40:09 +00:00
parent 05cd134de9
commit ff1a7ec42e
18 changed files with 1868 additions and 1024 deletions

View file

@ -1,3 +1,9 @@
3 September 2008: Wouter
- options for 'DNS Rebinding' protection: private-address and
private-domain.
- dnstree for reuse of routines that help with domain, addr lookups.
- private-address and private-domain config option read, stored.
2 September 2008: Wouter 2 September 2008: Wouter
- DoS protection features. Queries are jostled out to make room. - DoS protection features. Queries are jostled out to make room.
- testbound can pass time, increasing the internal timer. - testbound can pass time, increasing the internal timer.

View file

@ -141,7 +141,7 @@ server:
# access-control: ::0/0 refuse # access-control: ::0/0 refuse
# access-control: ::1 allow # access-control: ::1 allow
# access-control: ::ffff:127.0.0.1 allow # access-control: ::ffff:127.0.0.1 allow
# if given, a chroot(2) is done to the given directory. # if given, a chroot(2) is done to the given directory.
# i.e. you can chroot to the working directory, for example, # i.e. you can chroot to the working directory, for example,
# for extra security, but make sure all files are in that directory. # for extra security, but make sure all files are in that directory.
@ -243,6 +243,22 @@ server:
# resolution will fail for them. A solution is on the TODO list. # resolution will fail for them. A solution is on the TODO list.
# use-caps-for-id: no # use-caps-for-id: no
# Enforce privacy of these addresses. Strips them away from answers.
# It may cause DNSSEC validation to additionally mark it as bogus.
# Protects against 'DNS Rebinding' (uses browser as network proxy).
# Only 'private-domain' and 'local-data' names are allowed to have
# these private addresses. No default.
# private-address: 10.0.0.0/8
# private-address: 172.16.0.0/12
# private-address: 192.168.0.0/16
# private-address: 192.254.0.0/16
# private-address: fd00::/8
# private-address: fe80::/10
# Allow the domain (and its subdomains) to contain private addresses.
# local-data statements are allowed to contain private addresses too.
# private-domain: "example.com"
# Do not query the following addresses. No DNS queries are sent there. # Do not query the following addresses. No DNS queries are sent there.
# List one address per entry. List classless netblocks with /size, # List one address per entry. List classless netblocks with /size,
# do-not-query-address: 127.0.0.1/8 # do-not-query-address: 127.0.0.1/8

View file

@ -70,6 +70,7 @@ like dnswall does. Allow certain subdomains to do it, config options.
* IPv6 reverse, IP4 reverse local-data shorthand for PTR records (?). * IPv6 reverse, IP4 reverse local-data shorthand for PTR records (?).
cumbersome to reverse notate by hand for the operator. For local-data. cumbersome to reverse notate by hand for the operator. For local-data.
local-reverse-data: "1.2.3.4 mypc.example.com" local-reverse-data: "1.2.3.4 mypc.example.com"
* dns-0x20 fallback TODO item. Consider.
*** from draft resolver-mitigation *** from draft resolver-mitigation
* Should be an option? (Not right now) * Should be an option? (Not right now)

View file

@ -172,6 +172,7 @@ int
donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg) donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg)
{ {
free(dq->tree); free(dq->tree);
regional_free_all(dq->region);
dq->tree = rbtree_create(donotq_cmp); dq->tree = rbtree_create(donotq_cmp);
if(!dq->tree) if(!dq->tree)
return 0; return 0;

182
iterator/iter_priv.c Normal file
View file

@ -0,0 +1,182 @@
/*
* iterator/iter_priv.c - iterative resolver private address and domain store
*
* Copyright (c) 2008, 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 private addresses and lookup fast.
*/
#include "config.h"
#include "iterator/iter_priv.h"
#include "util/regional.h"
#include "util/log.h"
#include "util/config_file.h"
#include "util/data/dname.h"
#include "util/net_help.h"
#include "util/storage/dnstree.h"
struct iter_priv* priv_create()
{
struct iter_priv* priv = (struct iter_priv*)calloc(1, sizeof(*priv));
if(!priv)
return NULL;
priv->region = regional_create();
if(!priv->region) {
priv_delete(priv);
return NULL;
}
addr_tree_init(&priv->a);
name_tree_init(&priv->n);
return priv;
}
void priv_delete(struct iter_priv* priv)
{
if(!priv) return;
regional_destroy(priv->region);
free(priv);
}
/** Read private-addr declarations from config */
static int read_addrs(struct iter_priv* priv, struct config_file* cfg)
{
/* parse addresses, report errors, insert into tree */
struct config_strlist* p;
struct addr_tree_node* n;
struct sockaddr_storage addr;
int net;
socklen_t addrlen;
for(p = cfg->private_address; p; p = p->next) {
log_assert(p->str);
if(!netblockstrtoaddr(p->str, UNBOUND_DNS_PORT, &addr,
&addrlen, &net)) {
log_err("cannot parse private-address: %s", p->str);
return 0;
}
n = (struct addr_tree_node*)regional_alloc(priv->region,
sizeof(*n));
if(!n) {
log_err("out of memory");
return 0;
}
if(!addr_tree_insert(&priv->a, n, &addr, addrlen, net)) {
verbose(VERB_QUERY, "ignoring duplicate "
"private-address: %s", p->str);
}
}
return 1;
}
/** Read private-domain declarations from config */
static int read_names(struct iter_priv* priv, struct config_file* cfg)
{
/* parse names, report errors, insert into tree */
struct config_strlist* p;
struct name_tree_node* n;
uint8_t* nm;
size_t nm_len;
int nm_labs;
ldns_rdf* rdf;
for(p = cfg->private_address; p; p = p->next) {
log_assert(p->str);
rdf = ldns_dname_new_frm_str(p->str);
if(!rdf) {
log_err("cannot parse private-domain: %s", p->str);
return 0;
}
nm = ldns_rdf_data(rdf);
nm_labs = dname_count_size_labels(nm, &nm_len);
nm = (uint8_t*)regional_alloc_init(priv->region, nm, nm_len);
ldns_rdf_deep_free(rdf);
if(!nm) {
log_err("out of memory");
return 0;
}
n = (struct name_tree_node*)regional_alloc(priv->region,
sizeof(*n));
if(!n) {
log_err("out of memory");
return 0;
}
if(!name_tree_insert(&priv->n, n, nm, nm_len, nm_labs,
LDNS_RR_CLASS_IN)) {
verbose(VERB_QUERY, "ignoring duplicate "
"private-domain: %s", p->str);
}
}
return 1;
}
int priv_apply_cfg(struct iter_priv* priv, struct config_file* cfg)
{
/* empty the current contents */
regional_free_all(priv->region);
addr_tree_init(&priv->a);
name_tree_init(&priv->n);
/* read new contents */
if(!read_addrs(priv, cfg))
return 0;
if(!read_names(priv, cfg))
return 0;
/* prepare for lookups */
addr_tree_init_parents(&priv->a);
name_tree_init_parents(&priv->n);
return 1;
}
int priv_lookup_addr(struct iter_priv* priv, struct sockaddr_storage* addr,
socklen_t addrlen)
{
return addr_tree_lookup(&priv->a, addr, addrlen) != NULL;
}
int priv_lookup_name(struct iter_priv* priv, uint8_t* name, uint16_t dclass)
{
size_t len;
int labs = dname_count_size_labels(name, &len);
return name_tree_lookup(&priv->n, name, len, labs, dclass) != NULL;
}
size_t priv_get_mem(struct iter_priv* priv)
{
if(!priv) return 0;
return sizeof(*priv) + regional_get_mem(priv->region);
}

117
iterator/iter_priv.h Normal file
View file

@ -0,0 +1,117 @@
/*
* iterator/iter_priv.h - iterative resolver private address and domain store
*
* Copyright (c) 2008, 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 private addresses and lookup fast.
*/
#ifndef ITERATOR_ITER_PRIV_H
#define ITERATOR_ITER_PRIV_H
#include "util/rbtree.h"
struct iter_env;
struct config_file;
struct regional;
/**
* Iterator priv structure
*/
struct iter_priv {
/** regional for allocation */
struct regional* region;
/**
* Tree of the address spans that are blocked.
* contents of type addr_tree_node.
* No further data need, only presence or absence.
*/
rbtree_t a;
/**
* Tree of the domains spans that are allowed to contain
* the blocked address spans.
* contents of type name_tree_node.
* No further data need, only presence or absence.
*/
rbtree_t n;
};
/**
* Create priv structure
* @return new structure or NULL on error.
*/
struct iter_priv* priv_create();
/**
* Delete priv structure.
* @param priv: to delete.
*/
void priv_delete(struct iter_priv* priv);
/**
* Process priv config.
* @param priv: where to store.
* @param cfg: config options.
* @return 0 on error.
*/
int priv_apply_cfg(struct iter_priv* priv, struct config_file* cfg);
/**
* See if an address is blocked.
* @param priv: 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 priv_lookup_addr(struct iter_priv* priv, struct sockaddr_storage* addr,
socklen_t addrlen);
/**
* See if a name is whitelisted.
* @param priv: structure for address storage.
* @param name: name to check.
* @param dclass: class to check.
* @return: true if the name is OK. false if unlisted.
*/
int priv_lookup_name(struct iter_priv* priv, uint8_t* name, uint16_t dclass);
/**
* Get memory used by priv structure.
* @param priv: structure for address storage.
* @return bytes in use.
*/
size_t priv_get_mem(struct iter_priv* priv);
#endif /* ITERATOR_ITER_PRIV_H */

View file

@ -46,6 +46,7 @@
#include "iterator/iter_fwd.h" #include "iterator/iter_fwd.h"
#include "iterator/iter_donotq.h" #include "iterator/iter_donotq.h"
#include "iterator/iter_delegpt.h" #include "iterator/iter_delegpt.h"
#include "iterator/iter_priv.h"
#include "services/cache/infra.h" #include "services/cache/infra.h"
#include "services/cache/dns.h" #include "services/cache/dns.h"
#include "services/cache/rrset.h" #include "services/cache/rrset.h"
@ -123,6 +124,12 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
log_err("Could not set donotqueryaddresses"); log_err("Could not set donotqueryaddresses");
return 0; return 0;
} }
if(!iter_env->priv)
iter_env->priv = priv_create();
if(!iter_env->priv || !priv_apply_cfg(iter_env->priv, cfg)) {
log_err("Could not set private addresses");
return 0;
}
iter_env->supports_ipv6 = cfg->do_ip6; iter_env->supports_ipv6 = cfg->do_ip6;
return 1; return 1;
} }

View file

@ -50,6 +50,7 @@ struct iter_hints;
struct iter_forwards; struct iter_forwards;
struct iter_donotq; struct iter_donotq;
struct iter_prep_list; struct iter_prep_list;
struct iter_priv;
/** max number of query restarts. Determines max number of CNAME chain. */ /** max number of query restarts. Determines max number of CNAME chain. */
#define MAX_RESTART_COUNT 8 #define MAX_RESTART_COUNT 8
@ -92,6 +93,9 @@ struct iter_env {
/** A set of inetaddrs that should never be queried. */ /** A set of inetaddrs that should never be queried. */
struct iter_donotq* donotq; struct iter_donotq* donotq;
/** private address space and private domains */
struct iter_priv* priv;
/** The maximum dependency depth that this resolver will pursue. */ /** The maximum dependency depth that this resolver will pursue. */
int max_dependency_depth; int max_dependency_depth;

View file

@ -131,6 +131,8 @@ config_create()
cfg->harden_dnssec_stripped = 1; cfg->harden_dnssec_stripped = 1;
cfg->harden_referral_path = 0; cfg->harden_referral_path = 0;
cfg->use_caps_bits_for_id = 0; cfg->use_caps_bits_for_id = 0;
cfg->private_address = NULL;
cfg->private_domain = NULL;
cfg->hide_identity = 0; cfg->hide_identity = 0;
cfg->hide_version = 0; cfg->hide_version = 0;
cfg->identity = NULL; cfg->identity = NULL;
@ -295,6 +297,13 @@ int config_set_option(struct config_file* cfg, const char* opt,
} else if(strcmp(opt, "harden-dnssec-stripped:") == 0) { } else if(strcmp(opt, "harden-dnssec-stripped:") == 0) {
IS_YES_OR_NO; IS_YES_OR_NO;
cfg->harden_dnssec_stripped = (strcmp(val, "yes") == 0); cfg->harden_dnssec_stripped = (strcmp(val, "yes") == 0);
} else if(strcmp(opt, "harden-referral-path:") == 0) {
IS_YES_OR_NO;
cfg->harden_referral_path = (strcmp(val, "yes") == 0);
} else if(strcmp(opt, "private-address:") == 0) {
return cfg_strlist_insert(&cfg->private_address, strdup(val));
} else if(strcmp(opt, "private-domain:") == 0) {
return cfg_strlist_insert(&cfg->private_domain, strdup(val));
} else if(strcmp(opt, "do-not-query-localhost:") == 0) { } else if(strcmp(opt, "do-not-query-localhost:") == 0) {
IS_YES_OR_NO; IS_YES_OR_NO;
cfg->donotquery_localhost = (strcmp(val, "yes") == 0); cfg->donotquery_localhost = (strcmp(val, "yes") == 0);
@ -462,6 +471,8 @@ config_delete(struct config_file* cfg)
free(cfg->version); free(cfg->version);
free(cfg->module_conf); free(cfg->module_conf);
free(cfg->outgoing_avail_ports); free(cfg->outgoing_avail_ports);
config_delstrlist(cfg->private_address);
config_delstrlist(cfg->private_domain);
config_delstrlist(cfg->trust_anchor_file_list); config_delstrlist(cfg->trust_anchor_file_list);
config_delstrlist(cfg->trusted_keys_file_list); config_delstrlist(cfg->trusted_keys_file_list);
config_delstrlist(cfg->trust_anchor_list); config_delstrlist(cfg->trust_anchor_list);

View file

@ -147,6 +147,10 @@ struct config_file {
int harden_referral_path; int harden_referral_path;
/** use 0x20 bits in query as random ID bits */ /** use 0x20 bits in query as random ID bits */
int use_caps_bits_for_id; int use_caps_bits_for_id;
/** strip away these private addrs from answers, no DNS Rebinding */
struct config_strlist* private_address;
/** allow domain (and subdomains) to use private address space */
struct config_strlist* private_domain;
/** chrootdir, if not "" or chroot will be done */ /** chrootdir, if not "" or chroot will be done */
char* chrootdir; char* chrootdir;

File diff suppressed because it is too large Load diff

View file

@ -149,6 +149,8 @@ harden-glue{COLON} { YDOUT; return VAR_HARDEN_GLUE;}
harden-dnssec-stripped{COLON} { YDOUT; return VAR_HARDEN_DNNSEC_STRIPPED;} harden-dnssec-stripped{COLON} { YDOUT; return VAR_HARDEN_DNNSEC_STRIPPED;}
harden-referral-path{COLON} { YDOUT; return VAR_HARDEN_REFERRAL_PATH;} harden-referral-path{COLON} { YDOUT; return VAR_HARDEN_REFERRAL_PATH;}
use-caps-for-id{COLON} { YDOUT; return VAR_USE_CAPS_FOR_ID;} use-caps-for-id{COLON} { YDOUT; return VAR_USE_CAPS_FOR_ID;}
private-address{COLON} { YDOUT; return VAR_PRIVATE_ADDRESS;}
private-domain{COLON} { YDOUT; return VAR_PRIVATE_DOMAIN;}
stub-zone{COLON} { YDOUT; return VAR_STUB_ZONE;} stub-zone{COLON} { YDOUT; return VAR_STUB_ZONE;}
name{COLON} { YDOUT; return VAR_NAME;} name{COLON} { YDOUT; return VAR_NAME;}
stub-addr{COLON} { YDOUT; return VAR_STUB_ADDR;} stub-addr{COLON} { YDOUT; return VAR_STUB_ADDR;}

File diff suppressed because it is too large Load diff

View file

@ -121,7 +121,9 @@
VAR_DLV_ANCHOR_FILE = 337, VAR_DLV_ANCHOR_FILE = 337,
VAR_DLV_ANCHOR = 338, VAR_DLV_ANCHOR = 338,
VAR_NEG_CACHE_SIZE = 339, VAR_NEG_CACHE_SIZE = 339,
VAR_HARDEN_REFERRAL_PATH = 340 VAR_HARDEN_REFERRAL_PATH = 340,
VAR_PRIVATE_ADDRESS = 341,
VAR_PRIVATE_DOMAIN = 342
}; };
#endif #endif
/* Tokens. */ /* Tokens. */
@ -208,6 +210,8 @@
#define VAR_DLV_ANCHOR 338 #define VAR_DLV_ANCHOR 338
#define VAR_NEG_CACHE_SIZE 339 #define VAR_NEG_CACHE_SIZE 339
#define VAR_HARDEN_REFERRAL_PATH 340 #define VAR_HARDEN_REFERRAL_PATH 340
#define VAR_PRIVATE_ADDRESS 341
#define VAR_PRIVATE_DOMAIN 342
@ -219,7 +223,7 @@ typedef union YYSTYPE
char* str; char* str;
} }
/* Line 1489 of yacc.c. */ /* Line 1489 of yacc.c. */
#line 223 "util/configparser.h" #line 227 "util/configparser.h"
YYSTYPE; YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_DECLARED 1

View file

@ -91,7 +91,8 @@ extern struct config_parser_state* cfg_parser;
%token VAR_STATISTICS_INTERVAL VAR_DO_DAEMONIZE VAR_USE_CAPS_FOR_ID %token VAR_STATISTICS_INTERVAL VAR_DO_DAEMONIZE VAR_USE_CAPS_FOR_ID
%token VAR_STATISTICS_CUMULATIVE VAR_OUTGOING_PORT_PERMIT %token VAR_STATISTICS_CUMULATIVE VAR_OUTGOING_PORT_PERMIT
%token VAR_OUTGOING_PORT_AVOID VAR_DLV_ANCHOR_FILE VAR_DLV_ANCHOR %token VAR_OUTGOING_PORT_AVOID VAR_DLV_ANCHOR_FILE VAR_DLV_ANCHOR
%token VAR_NEG_CACHE_SIZE VAR_HARDEN_REFERRAL_PATH %token VAR_NEG_CACHE_SIZE VAR_HARDEN_REFERRAL_PATH VAR_PRIVATE_ADDRESS
%token VAR_PRIVATE_DOMAIN
%% %%
toplevelvars: /* empty */ | toplevelvars toplevelvar ; toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -135,7 +136,8 @@ content_server: server_num_threads | server_verbosity | server_port |
server_use_caps_for_id | server_statistics_cumulative | server_use_caps_for_id | server_statistics_cumulative |
server_outgoing_port_permit | server_outgoing_port_avoid | server_outgoing_port_permit | server_outgoing_port_avoid |
server_dlv_anchor_file | server_dlv_anchor | server_neg_cache_size | server_dlv_anchor_file | server_dlv_anchor | server_neg_cache_size |
server_harden_referral_path server_harden_referral_path | server_private_address |
server_private_domain
; ;
stubstart: VAR_STUB_ZONE stubstart: VAR_STUB_ZONE
{ {
@ -647,6 +649,20 @@ server_use_caps_for_id: VAR_USE_CAPS_FOR_ID STRING
free($2); free($2);
} }
; ;
server_private_address: VAR_PRIVATE_ADDRESS STRING
{
OUTYY(("P(server_private_address:%s)\n", $2));
if(!cfg_strlist_insert(&cfg_parser->cfg->private_address, $2))
yyerror("out of memory");
}
;
server_private_domain: VAR_PRIVATE_DOMAIN STRING
{
OUTYY(("P(server_private_domain:%s)\n", $2));
if(!cfg_strlist_insert(&cfg_parser->cfg->private_domain, $2))
yyerror("out of memory");
}
;
server_do_not_query_address: VAR_DO_NOT_QUERY_ADDRESS STRING server_do_not_query_address: VAR_DO_NOT_QUERY_ADDRESS STRING
{ {
OUTYY(("P(server_do_not_query_address:%s)\n", $2)); OUTYY(("P(server_do_not_query_address:%s)\n", $2));

View file

@ -65,6 +65,7 @@
#include "util/data/msgreply.h" #include "util/data/msgreply.h"
#include "util/data/packed_rrset.h" #include "util/data/packed_rrset.h"
#include "util/storage/slabhash.h" #include "util/storage/slabhash.h"
#include "util/storage/dnstree.h"
#include "util/locks.h" #include "util/locks.h"
#include "daemon/acl_list.h" #include "daemon/acl_list.h"
#include "libunbound/libworker.h" #include "libunbound/libworker.h"
@ -159,6 +160,8 @@ fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *))
else if(fptr == &stub_cmp) return 1; else if(fptr == &stub_cmp) return 1;
else if(fptr == &pending_cmp) return 1; else if(fptr == &pending_cmp) return 1;
else if(fptr == &serviced_cmp) return 1; else if(fptr == &serviced_cmp) return 1;
else if(fptr == &name_tree_compare) return 1;
else if(fptr == &addr_tree_compare) return 1;
else if(fptr == &order_lock_cmp) return 1; else if(fptr == &order_lock_cmp) return 1;
else if(fptr == &codeline_cmp) return 1; else if(fptr == &codeline_cmp) return 1;
else if(fptr == &nsec3_hash_cmp) return 1; else if(fptr == &nsec3_hash_cmp) return 1;

230
util/storage/dnstree.c Normal file
View file

@ -0,0 +1,230 @@
/*
* util/storage/dnstree.c - support for rbtree types suitable for DNS code.
*
* Copyright (c) 2008, 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 structures combining types and functions to
* manipulate those structures that help building DNS lookup trees.
*/
#include "config.h"
#include "util/storage/dnstree.h"
#include "util/data/dname.h"
#include "util/net_help.h"
int name_tree_compare(const void* k1, const void* k2)
{
struct name_tree_node* x = (struct name_tree_node*)k1;
struct name_tree_node* y = (struct name_tree_node*)k2;
int m;
if(x->dclass != y->dclass) {
if(x->dclass < y->dclass)
return -1;
return 1;
}
return dname_canon_lab_cmp(x->name, x->labs, y->name, y->labs, &m);
}
int addr_tree_compare(const void* k1, const void* k2)
{
struct addr_tree_node* n1 = (struct addr_tree_node*)k1;
struct addr_tree_node* n2 = (struct addr_tree_node*)k2;
int r = sockaddr_cmp_addr(&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;
}
void name_tree_init(rbtree_t* tree)
{
rbtree_init(tree, &name_tree_compare);
}
void addr_tree_init(rbtree_t* tree)
{
rbtree_init(tree, &addr_tree_compare);
}
int name_tree_insert(rbtree_t* tree, struct name_tree_node* node,
uint8_t* name, size_t len, int labs, uint16_t dclass)
{
node->node.key = node;
node->name = name;
node->len = len;
node->labs = labs;
node->dclass = dclass;
return rbtree_insert(tree, &node->node) != NULL;
}
int addr_tree_insert(rbtree_t* tree, struct addr_tree_node* node,
struct sockaddr_storage* addr, socklen_t addrlen, int net)
{
node->node.key = node;
memcpy(&node->addr, addr, addrlen);
node->addrlen = addrlen;
node->net = net;
return rbtree_insert(tree, &node->node) != NULL;
}
void addr_tree_init_parents(rbtree_t* tree)
{
struct addr_tree_node* node, *prev = NULL, *p;
int m;
RBTREE_FOR(node, struct addr_tree_node*, 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;
}
}
void name_tree_init_parents(rbtree_t* tree)
{
struct name_tree_node* node, *prev = NULL, *p;
int m;
RBTREE_FOR(node, struct name_tree_node*, tree) {
node->parent = NULL;
if(!prev || prev->dclass != node->dclass) {
prev = node;
continue;
}
(void)dname_lab_cmp(prev->name, prev->labs, node->name,
node->labs, &m); /* we know prev is smaller */
/* sort order like: . com. bla.com. zwb.com. net. */
/* find the previous, or parent-parent-parent */
for(p = prev; p; p = p->parent)
if(p->labs <= 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;
}
}
struct name_tree_node* name_tree_find(rbtree_t* tree, uint8_t* name,
size_t len, int labs, uint16_t dclass)
{
struct name_tree_node key;
key.node.key = &key;
key.name = name;
key.len = len;
key.labs = labs;
key.dclass = dclass;
return (struct name_tree_node*)rbtree_search(tree, &key);
}
struct name_tree_node* name_tree_lookup(rbtree_t* tree, uint8_t* name,
size_t len, int labs, uint16_t dclass)
{
rbnode_t* res = NULL;
struct name_tree_node *result;
struct name_tree_node key;
key.node.key = &key;
key.name = name;
key.len = len;
key.labs = labs;
key.dclass = dclass;
if(rbtree_find_less_equal(tree, &key, &res)) {
/* exact */
result = (struct name_tree_node*)res;
} else {
/* smaller element (or no element) */
int m;
result = (struct name_tree_node*)res;
if(!result || result->dclass != dclass)
return NULL;
/* count number of labels matched */
(void)dname_lab_cmp(result->name, result->labs, key.name,
key.labs, &m);
while(result) { /* go up until qname is subdomain of stub */
if(result->labs <= m)
break;
result = result->parent;
}
}
return result;
}
struct addr_tree_node* addr_tree_lookup(rbtree_t* tree,
struct sockaddr_storage* addr, socklen_t addrlen)
{
rbnode_t* res = NULL;
struct addr_tree_node* result;
struct addr_tree_node key;
key.node.key = &key;
memcpy(&key.addr, addr, addrlen);
key.addrlen = addrlen;
key.net = (addr_is_ip6(addr, addrlen)?128:32);
if(rbtree_find_less_equal(tree, &key, &res)) {
/* exact */
return (struct addr_tree_node*)res;
} else {
/* smaller element (or no element) */
int m;
result = (struct addr_tree_node*)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)
break;
result = result->parent;
}
}
return result;
}

184
util/storage/dnstree.h Normal file
View file

@ -0,0 +1,184 @@
/*
* util/storage/dnstree.h - support for rbtree types suitable for DNS code.
*
* Copyright (c) 2008, 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 structures combining types and functions to
* manipulate those structures that help building DNS lookup trees.
*/
#ifndef UTIL_STORAGE_DNSTREE_H
#define UTIL_STORAGE_DNSTREE_H
#include "util/rbtree.h"
/**
* Tree of domain names. Sorted first by class then by name.
* This is not sorted canonically, but fast.
* This can be looked up to obtain a closest encloser parent name.
*
* The tree itself is a rbtree_t.
* This is the element node put as first entry in the client structure.
*/
struct name_tree_node {
/** rbtree node, key is this struct : dclass and name */
rbnode_t node;
/** parent in tree */
struct name_tree_node* parent;
/** name in uncompressed wireformat */
uint8_t* name;
/** length of name */
size_t len;
/** labels in name */
int labs;
/** the class of the name (host order) */
uint16_t dclass;
};
/**
* Tree of IP addresses. Sorted first by protocol, then by bits.
* This can be looked up to obtain the enclosing subnet.
*
* The tree itself is a rbtree_t.
* This is the element node put as first entry in the client structure.
*/
struct addr_tree_node {
/** rbtree node, key is this struct : proto and subnet */
rbnode_t node;
/** parent in tree */
struct addr_tree_node* parent;
/** address */
struct sockaddr_storage addr;
/** length of addr */
socklen_t addrlen;
/** netblock size */
int net;
};
/**
* Init a name tree to be empty
* @param tree: to init.
*/
void name_tree_init(rbtree_t* tree);
/**
* insert element into name tree.
* @param tree: name tree
* @param node: node element (at start of a structure that caller
* has allocated).
* @param name: name to insert (wireformat)
* this node has been allocated by the caller and it itself inserted.
* @param len: length of name
* @param labs: labels in name
* @param dclass: class of name
* @return false on error (duplicate element).
*/
int name_tree_insert(rbtree_t* tree, struct name_tree_node* node,
uint8_t* name, size_t len, int labs, uint16_t dclass);
/**
* Initialize parent pointers in name tree.
* Should be performed after insertions are done, before lookups
* @param tree: name tree
*/
void name_tree_init_parents(rbtree_t* tree);
/**
* Lookup exact match in name tree
* @param tree: name tree
* @param name: wireformat name
* @param len: length of name
* @param labs: labels in name
* @param dclass: class of name
* @return node or NULL if not found.
*/
struct name_tree_node* name_tree_find(rbtree_t* tree, uint8_t* name,
size_t len, int labs, uint16_t dclass);
/**
* Lookup closest encloser in name tree.
* @param tree: name tree
* @param name: wireformat name
* @param len: length of name
* @param labs: labels in name
* @param dclass: class of name
* @return closest enclosing node (could be equal) or NULL if not found.
*/
struct name_tree_node* name_tree_lookup(rbtree_t* tree, uint8_t* name,
size_t len, int labs, uint16_t dclass);
/**
* Init addr tree to be empty.
* @param tree: to init.
*/
void addr_tree_init(rbtree_t* tree);
/**
* insert element into addr tree.
* @param tree: addr tree
* @param node: node element (at start of a structure that caller
* has allocated).
* @param addr: to insert (copied).
* @param addrlen: length of addr
* @param net: size of subnet.
* @return false on error (duplicate element).
*/
int addr_tree_insert(rbtree_t* tree, struct addr_tree_node* node,
struct sockaddr_storage* addr, socklen_t addrlen, int net);
/**
* Initialize parent pointers in addr tree.
* Should be performed after insertions are done, before lookups
* @param tree: addr tree
*/
void addr_tree_init_parents(rbtree_t* tree);
/**
* Lookup closest encloser in addr tree.
* @param tree: addr tree
* @param addr: to lookup.
* @param addrlen: length of addr
* @return closest enclosing node (could be equal) or NULL if not found.
*/
struct addr_tree_node* addr_tree_lookup(rbtree_t* tree,
struct sockaddr_storage* addr, socklen_t addrlen);
/** compare name tree nodes */
int name_tree_compare(const void* k1, const void* k2);
/** compare addr tree nodes */
int addr_tree_compare(const void* k1, const void* k2);
#endif /* UTIL_STORAGE_DNSTREE_H */