- caps-whitelist in unbound.conf allows whitelist of loadbalancers

that cannot work with caps-for-id or its fallback.


git-svn-id: file:///svn/unbound/trunk@3420 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2015-05-01 12:36:16 +00:00
parent b8eb1713e0
commit f03d3b870e
16 changed files with 2074 additions and 1944 deletions

View file

@ -691,7 +691,7 @@ iter_utils.lo iter_utils.o: $(srcdir)/iterator/iter_utils.c config.h $(srcdir)/i
$(srcdir)/util/fptr_wlist.h $(srcdir)/util/netevent.h $(srcdir)/util/tube.h $(srcdir)/services/mesh.h \
$(srcdir)/services/modstack.h $(srcdir)/validator/val_anchor.h $(srcdir)/validator/val_kcache.h \
$(srcdir)/validator/val_kentry.h $(srcdir)/validator/val_utils.h $(srcdir)/validator/val_sigcrypt.h \
$(srcdir)/sldns/sbuffer.h
$(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/str2wire.h
listen_dnsport.lo listen_dnsport.o: $(srcdir)/services/listen_dnsport.c config.h \
$(srcdir)/services/listen_dnsport.h $(srcdir)/util/netevent.h $(srcdir)/services/outside_network.h \
$(srcdir)/util/rbtree.h $(srcdir)/util/log.h $(srcdir)/util/config_file.h \

View file

@ -1,3 +1,7 @@
1 May 2015: Wouter
- caps-whitelist in unbound.conf allows whitelist of loadbalancers
that cannot work with caps-for-id or its fallback.
30 April 2015: Wouter
- Unit test for type ANY synthesis.

View file

@ -296,6 +296,10 @@ server:
# Use 0x20-encoded random bits in the query to foil spoof attempts.
# This feature is an experimental implementation of draft dns-0x20.
# use-caps-for-id: no
# Domains (and domains in them) without support for dns-0x20 and
# the fallback fails because they keep sending different answers.
# caps-whitelist: "licdn.com"
# Enforce privacy of these addresses. Strips them away from answers.
# It may cause DNSSEC validation to additionally mark it as bogus.

View file

@ -574,6 +574,12 @@ authority servers and checks if the reply still has the correct casing.
Disabled by default.
This feature is an experimental implementation of draft dns\-0x20.
.TP
.B caps\-whitelist: \fI<domain>
Whitelist the domain so that it does not receive caps\-for\-id perturbed
queries. For domains that do not support 0x20 and also fail with fallback
because they keep sending different answers, like some load balancers.
Can be given multiple times, for different domains.
.TP
.B private\-address: \fI<IP address or subnet>
Give IPv4 of IPv6 addresses or classless subnets. These are addresses
on your private network, and are not allowed to be returned for public

View file

@ -65,6 +65,7 @@
#include "validator/val_utils.h"
#include "validator/val_sigcrypt.h"
#include "sldns/sbuffer.h"
#include "sldns/str2wire.h"
/** time when nameserver glue is said to be 'recent' */
#define SUSPICION_RECENT_EXPIRY 86400
@ -105,6 +106,35 @@ read_fetch_policy(struct iter_env* ie, const char* str)
return 1;
}
/** apply config caps whitelist items to name tree */
static int
caps_white_apply_cfg(rbtree_t* ntree, struct config_file* cfg)
{
struct config_strlist* p;
for(p=cfg->caps_whitelist; p; p=p->next) {
struct name_tree_node* n;
size_t len;
uint8_t* nm = sldns_str2wire_dname(p->str, &len);
if(!nm) {
log_err("could not parse %s", p->str);
return 0;
}
n = (struct name_tree_node*)calloc(1, sizeof(*n));
n->node.key = n;
n->name = nm;
n->len = len;
n->labs = dname_count_labels(nm);
n->dclass = LDNS_RR_CLASS_IN;
if(!name_tree_insert(ntree, n, nm, len, n->labs, n->dclass)) {
/* duplicate element ignored, idempotent */
free(n->name);
free(n);
}
}
name_tree_init_parents(ntree);
return 1;
}
int
iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
{
@ -128,6 +158,16 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
log_err("Could not set private addresses");
return 0;
}
if(cfg->caps_whitelist) {
if(!iter_env->caps_white)
iter_env->caps_white = rbtree_create(name_tree_compare);
if(!iter_env->caps_white || !caps_white_apply_cfg(
iter_env->caps_white, cfg)) {
log_err("Could not set capsforid whitelist");
return 0;
}
}
iter_env->supports_ipv6 = cfg->do_ip6;
iter_env->supports_ipv4 = cfg->do_ip4;
return 1;

View file

@ -84,6 +84,16 @@ iter_init(struct module_env* env, int id)
return 1;
}
/** delete caps_whitelist element */
static void
caps_free(struct rbnode_t* n, void* ATTR_UNUSED(d))
{
if(n) {
free(((struct name_tree_node*)n)->name);
free(n);
}
}
void
iter_deinit(struct module_env* env, int id)
{
@ -94,6 +104,10 @@ iter_deinit(struct module_env* env, int id)
free(iter_env->target_fetch_policy);
priv_delete(iter_env->priv);
donotq_delete(iter_env->donotq);
if(iter_env->caps_white) {
traverse_postorder(iter_env->caps_white, caps_free, NULL);
free(iter_env->caps_white);
}
free(iter_env);
env->modinfo[id] = NULL;
}
@ -459,6 +473,16 @@ handle_cname_response(struct module_qstate* qstate, struct iter_qstate* iq,
return 1;
}
/** see if target name is caps-for-id whitelisted */
static int
is_caps_whitelisted(struct iter_env* ie, struct iter_qstate* iq)
{
if(!ie->caps_white) return 0; /* no whitelist, or no capsforid */
return name_tree_lookup(ie->caps_white, iq->qchase.qname,
iq->qchase.qname_len, dname_count_labels(iq->qchase.qname),
iq->qchase.qclass) != NULL;
}
/** create target count structure for this query */
static void
target_count_create(struct iter_qstate* iq)
@ -1965,8 +1989,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
iq->qchase.qname, iq->qchase.qname_len,
iq->qchase.qtype, iq->qchase.qclass,
iq->chase_flags | (iq->chase_to_rd?BIT_RD:0), EDNS_DO|BIT_CD,
iq->dnssec_expected, iq->caps_fallback, &target->addr,
target->addrlen, iq->dp->name, iq->dp->namelen, qstate);
iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted(
ie, iq), &target->addr, target->addrlen, iq->dp->name,
iq->dp->namelen, qstate);
if(!outq) {
log_addr(VERB_DETAIL, "error sending query to auth server",
&target->addr, target->addrlen);

View file

@ -51,6 +51,7 @@ struct iter_forwards;
struct iter_donotq;
struct iter_prep_list;
struct iter_priv;
struct rbtree_t;
/** max number of targets spawned for a query and its subqueries */
#define MAX_TARGET_COUNT 32
@ -96,6 +97,9 @@ struct iter_env {
/** private address space and private domains */
struct iter_priv* priv;
/** whitelist for capsforid names */
struct rbtree_t* caps_white;
/** The maximum dependency depth that this resolver will pursue. */
int max_dependency_depth;

View file

@ -1510,7 +1510,8 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
log_assert(rem); /* should have been present */
sq->to_be_deleted = 1;
verbose(VERB_ALGO, "svcd callbacks start");
if(sq->outnet->use_caps_for_id && error == NETEVENT_NOERROR && c) {
if(sq->outnet->use_caps_for_id && error == NETEVENT_NOERROR && c &&
!sq->nocaps) {
/* noerror and nxdomain must have a qname in reply */
if(sldns_buffer_read_u16_at(c->buffer, 4) == 0 &&
(LDNS_RCODE_WIRE(sldns_buffer_begin(c->buffer))

BIN
testdata/fwd_capsid_white.tpkg vendored Normal file

Binary file not shown.

View file

@ -173,6 +173,7 @@ config_create(void)
cfg->harden_referral_path = 0;
cfg->harden_algo_downgrade = 1;
cfg->use_caps_bits_for_id = 0;
cfg->caps_whitelist = NULL;
cfg->private_address = NULL;
cfg->private_domain = NULL;
cfg->unwanted_threshold = 0;
@ -416,6 +417,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_YNO("harden-referral-path:", harden_referral_path)
else S_YNO("harden-algo-downgrade:", harden_algo_downgrade)
else S_YNO("use-caps-for-id", use_caps_bits_for_id)
else S_STRLIST("caps-whitelist:", caps_whitelist)
else S_SIZET_OR_ZERO("unwanted-reply-threshold:", unwanted_threshold)
else S_STRLIST("private-address:", private_address)
else S_STRLIST("private-domain:", private_domain)
@ -685,6 +687,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_YNO(opt, "harden-referral-path", harden_referral_path)
else O_YNO(opt, "harden-algo-downgrade", harden_algo_downgrade)
else O_YNO(opt, "use-caps-for-id", use_caps_bits_for_id)
else O_LST(opt, "caps-whitelist", caps_whitelist)
else O_DEC(opt, "unwanted-reply-threshold", unwanted_threshold)
else O_YNO(opt, "do-not-query-localhost", donotquery_localhost)
else O_STR(opt, "module-config", module_conf)
@ -918,6 +921,7 @@ config_delete(struct config_file* cfg)
free(cfg->version);
free(cfg->module_conf);
free(cfg->outgoing_avail_ports);
config_delstrlist(cfg->caps_whitelist);
config_delstrlist(cfg->private_address);
config_delstrlist(cfg->private_domain);
config_delstrlist(cfg->auto_trust_anchor_file_list);

View file

@ -179,6 +179,8 @@ struct config_file {
int harden_algo_downgrade;
/** use 0x20 bits in query as random ID bits */
int use_caps_bits_for_id;
/** 0x20 whitelist, domains that do not use capsforid */
struct config_strlist* caps_whitelist;
/** strip away these private addrs from answers, no DNS Rebinding */
struct config_strlist* private_address;
/** allow domain (and subdomains) to use private address space */

File diff suppressed because it is too large Load diff

View file

@ -259,6 +259,7 @@ harden-below-nxdomain{COLON} { YDVAR(1, VAR_HARDEN_BELOW_NXDOMAIN) }
harden-referral-path{COLON} { YDVAR(1, VAR_HARDEN_REFERRAL_PATH) }
harden-algo-downgrade{COLON} { YDVAR(1, VAR_HARDEN_ALGO_DOWNGRADE) }
use-caps-for-id{COLON} { YDVAR(1, VAR_USE_CAPS_FOR_ID) }
caps-whitelist{COLON} { YDVAR(1, VAR_CAPS_WHITELIST) }
unwanted-reply-threshold{COLON} { YDVAR(1, VAR_UNWANTED_REPLY_THRESHOLD) }
private-address{COLON} { YDVAR(1, VAR_PRIVATE_ADDRESS) }
private-domain{COLON} { YDVAR(1, VAR_PRIVATE_DOMAIN) }

File diff suppressed because it is too large Load diff

View file

@ -201,7 +201,8 @@ extern int yydebug;
VAR_RATELIMIT_SIZE = 410,
VAR_RATELIMIT_FOR_DOMAIN = 411,
VAR_RATELIMIT_BELOW_DOMAIN = 412,
VAR_RATELIMIT_FACTOR = 413
VAR_RATELIMIT_FACTOR = 413,
VAR_CAPS_WHITELIST = 414
};
#endif
/* Tokens. */
@ -361,6 +362,7 @@ extern int yydebug;
#define VAR_RATELIMIT_FOR_DOMAIN 411
#define VAR_RATELIMIT_BELOW_DOMAIN 412
#define VAR_RATELIMIT_FACTOR 413
#define VAR_CAPS_WHITELIST 414
@ -374,7 +376,7 @@ typedef union YYSTYPE
/* Line 2058 of yacc.c */
#line 378 "util/configparser.h"
#line 380 "util/configparser.h"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */

View file

@ -121,6 +121,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_HARDEN_ALGO_DOWNGRADE VAR_IP_TRANSPARENT
%token VAR_RATELIMIT VAR_RATELIMIT_SLABS VAR_RATELIMIT_SIZE
%token VAR_RATELIMIT_FOR_DOMAIN VAR_RATELIMIT_BELOW_DOMAIN VAR_RATELIMIT_FACTOR
%token VAR_CAPS_WHITELIST
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -183,7 +184,8 @@ content_server: server_num_threads | server_verbosity | server_port |
server_infra_cache_min_rtt | server_harden_algo_downgrade |
server_ip_transparent | server_ratelimit | server_ratelimit_slabs |
server_ratelimit_size | server_ratelimit_for_domain |
server_ratelimit_below_domain | server_ratelimit_factor
server_ratelimit_below_domain | server_ratelimit_factor |
server_caps_whitelist
;
stubstart: VAR_STUB_ZONE
{
@ -882,6 +884,13 @@ server_use_caps_for_id: VAR_USE_CAPS_FOR_ID STRING_ARG
free($2);
}
;
server_caps_whitelist: VAR_CAPS_WHITELIST STRING_ARG
{
OUTYY(("P(server_caps_whitelist:%s)\n", $2));
if(!cfg_strlist_insert(&cfg_parser->cfg->caps_whitelist, $2))
yyerror("out of memory");
}
;
server_private_address: VAR_PRIVATE_ADDRESS STRING_ARG
{
OUTYY(("P(server_private_address:%s)\n", $2));