unwanted reply threshold like in the draft.

git-svn-id: file:///svn/unbound/trunk@1321 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2008-10-22 14:36:46 +00:00
parent 60d8b26ba1
commit 6cebdd2baf
16 changed files with 1362 additions and 1240 deletions

View file

@ -1042,7 +1042,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
cfg->do_tcp?cfg->outgoing_num_tcp:0,
worker->daemon->env->infra_cache, worker->rndstate,
cfg->use_caps_bits_for_id, worker->ports, worker->numports);
cfg->use_caps_bits_for_id, worker->ports, worker->numports,
cfg->unwanted_threshold, &worker_alloc_cleanup, worker);
if(!worker->back) {
log_err("could not create outgoing sockets");
worker_delete(worker);

View file

@ -5,6 +5,9 @@
- new stub-prime: yesno option. Default is off, so it does not prime.
can be turned on to get same behaviour as previous unbound release.
- made automated test that checks if builtin root hints are uptodate.
- finished draft-wijngaards-dnsext-resolver-side-mitigation
implementation. The unwanted-reply-threshold can be set.
- fixup so fptr_whitelist test in alloc.c works.
21 October 2008: Wouter
- fix update-anchors.sh, so it does not report different RR order

View file

@ -261,6 +261,13 @@ server:
# Allow the domain (and its subdomains) to contain private addresses.
# local-data statements are allowed to contain private addresses too.
# private-domain: "example.com"
# If nonzero, unwanted replies are not only reported in statistics,
# but also a running total is kept per thread. If it reaches the
# threshold, a warning is printed and a defensive action is taken,
# the cache is cleared to flush potential poison out of it.
# A suggested value is 10000000, the default is 0 (turned off).
# unwanted-reply-threshold: 0
# Do not query the following addresses. No DNS queries are sent there.
# List one address per entry. List classless netblocks with /size,

View file

@ -446,6 +446,13 @@ Allow this domain, and all its subdomains to contain private addresses.
Give multiple times to allow multiple domain names to contain private
addresses. Default is none.
.TP
.B unwanted\-reply\-threshold: \fI<number>
If set, a total number of unwanted replies is kept track of in every thread.
When it reaches the threshold, a defensive action is taken and a warning
is printed to the log. The defensive action is to clear the rrset and
message caches, hopefully flushing away any poison. A value of 10 million
is suggested. Default is 0 (turned off).
.TP
.B do\-not\-query\-address: \fI<IP address>
Do not query the given IP address. Can be IP4 or IP6. Append /num to
indicate a classless delegation netblock, for example like

View file

@ -159,7 +159,8 @@ libworker_setup(struct ub_ctx* ctx, int is_bg)
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
cfg->do_tcp?cfg->outgoing_num_tcp:0,
w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
ports, numports);
ports, numports, cfg->unwanted_threshold,
&libworker_alloc_cleanup, w);
if(!w->is_bg || w->is_bg_thread) {
lock_basic_unlock(&ctx->cfglock);
}

View file

@ -330,6 +330,17 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
verbose(VERB_QUERY, "received unwanted or unsolicited udp reply dropped.");
log_buf(VERB_ALGO, "dropped message", c->buffer);
outnet->unwanted_replies++;
if(outnet->unwanted_threshold && ++outnet->unwanted_total
>= outnet->unwanted_threshold) {
log_warn("unwanted reply total reached threshold (%u)"
" you may be under attack."
" defensive action: clearing the cache",
(unsigned)outnet->unwanted_threshold);
fptr_ok(fptr_whitelist_alloc_cleanup(
outnet->unwanted_action));
(*outnet->unwanted_action)(outnet->unwanted_param);
outnet->unwanted_total = 0;
}
return 0;
}
@ -339,6 +350,17 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
verbose(VERB_QUERY, "received reply id,addr on wrong port. "
"dropped.");
outnet->unwanted_replies++;
if(outnet->unwanted_threshold && ++outnet->unwanted_total
>= outnet->unwanted_threshold) {
log_warn("unwanted reply total reached threshold (%u)"
" you may be under attack."
" defensive action: clearing the cache",
(unsigned)outnet->unwanted_threshold);
fptr_ok(fptr_whitelist_alloc_cleanup(
outnet->unwanted_action));
(*outnet->unwanted_action)(outnet->unwanted_param);
outnet->unwanted_total = 0;
}
return 0;
}
comm_timer_disable(p->timer);
@ -444,7 +466,8 @@ outside_network_create(struct comm_base *base, size_t bufsize,
size_t num_ports, char** ifs, int num_ifs, int do_ip4,
int do_ip6, size_t num_tcp, struct infra_cache* infra,
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
int numavailports)
int numavailports, size_t unwanted_threshold,
void (*unwanted_action)(void*), void* unwanted_param)
{
struct outside_network* outnet = (struct outside_network*)
calloc(1, sizeof(struct outside_network));
@ -459,6 +482,9 @@ outside_network_create(struct comm_base *base, size_t bufsize,
outnet->infra = infra;
outnet->rnd = rnd;
outnet->svcd_overhead = 0;
outnet->unwanted_threshold = unwanted_threshold;
outnet->unwanted_action = unwanted_action;
outnet->unwanted_param = unwanted_param;
outnet->use_caps_for_id = use_caps_for_id;
if(numavailports == 0) {
log_err("no outgoing ports available");

View file

@ -76,8 +76,17 @@ struct outside_network {
size_t svcd_overhead;
/** use x20 bits to encode additional ID random bits */
int use_caps_for_id;
/** number of unwanted replies received */
/** number of unwanted replies received (for statistics) */
size_t unwanted_replies;
/** cumulative total of unwanted replies (for defense) */
size_t unwanted_total;
/** threshold when to take defensive action. If 0 then never. */
size_t unwanted_threshold;
/** what action to take, called when defensive action is needed */
void (*unwanted_action)(void*);
/** user param for action */
void* unwanted_param;
/** linked list of available commpoints, unused file descriptors,
* for use as outgoing UDP ports. cp.fd=-1 in them. */
@ -334,13 +343,17 @@ struct serviced_query {
* @param use_caps_for_id: enable to use 0x20 bits to encode id randomness.
* @param availports: array of available ports.
* @param numavailports: number of available ports in array.
* @param unwanted_threshold: when to take defensive action.
* @param unwanted_action: the action to take.
* @param unwanted_param: user parameter to action.
* @return: the new structure (with no pending answers) or NULL on error.
*/
struct outside_network* outside_network_create(struct comm_base* base,
size_t bufsize, size_t num_ports, char** ifs, int num_ifs,
int do_ip4, int do_ip6, size_t num_tcp, struct infra_cache* infra,
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
int numavailports);
int numavailports, size_t unwanted_threshold,
void (*unwanted_action)(void*), void* unwanted_param);
/**
* Delete outside_network structure.

View file

@ -722,10 +722,12 @@ outside_network_create(struct comm_base* base, size_t bufsize,
struct infra_cache* ATTR_UNUSED(infra),
struct ub_randstate* ATTR_UNUSED(rnd),
int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports),
int ATTR_UNUSED(numavailports))
int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold),
void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param))
{
struct outside_network* outnet = calloc(1,
sizeof(struct outside_network));
(void)unwanted_action;
if(!outnet)
return NULL;
outnet->base = base;

View file

@ -169,7 +169,7 @@ alloc_get_id(struct alloc_cache* alloc)
uint64_t id = alloc->next_id++;
if(id == alloc->last_id) {
log_warn("rrset alloc: out of 64bit ids. Clearing cache.");
fptr_whitelist_alloc_cleanup(alloc->cleanup);
fptr_ok(fptr_whitelist_alloc_cleanup(alloc->cleanup));
(*alloc->cleanup)(alloc->cleanup_arg);
/* start back at first number */ /* like in alloc_init*/

View file

@ -135,6 +135,7 @@ config_create()
cfg->use_caps_bits_for_id = 0;
cfg->private_address = NULL;
cfg->private_domain = NULL;
cfg->unwanted_threshold = 0;
cfg->hide_identity = 0;
cfg->hide_version = 0;
cfg->identity = NULL;
@ -325,6 +326,9 @@ int config_set_option(struct config_file* cfg, const char* opt,
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, "unwanted-reply-threshold:") == 0) {
IS_NUMBER_OR_ZERO;
cfg->unwanted_threshold = (size_t)atoi(val);
} else if(strcmp(opt, "do-not-query-localhost:") == 0) {
IS_YES_OR_NO;
cfg->donotquery_localhost = (strcmp(val, "yes") == 0);

View file

@ -155,6 +155,8 @@ struct config_file {
struct config_strlist* private_address;
/** allow domain (and subdomains) to use private address space */
struct config_strlist* private_domain;
/** what threshold for unwanted action. */
size_t unwanted_threshold;
/** chrootdir, if not "" or chroot will be done */
char* chrootdir;

File diff suppressed because it is too large Load diff

View file

@ -150,6 +150,7 @@ harden-glue{COLON} { YDOUT; return VAR_HARDEN_GLUE;}
harden-dnssec-stripped{COLON} { YDOUT; return VAR_HARDEN_DNNSEC_STRIPPED;}
harden-referral-path{COLON} { YDOUT; return VAR_HARDEN_REFERRAL_PATH;}
use-caps-for-id{COLON} { YDOUT; return VAR_USE_CAPS_FOR_ID;}
unwanted-reply-threshold{COLON} { YDOUT; return VAR_UNWANTED_REPLY_THRESHOLD;}
private-address{COLON} { YDOUT; return VAR_PRIVATE_ADDRESS;}
private-domain{COLON} { YDOUT; return VAR_PRIVATE_DOMAIN;}
stub-zone{COLON} { YDOUT; return VAR_STUB_ZONE;}

File diff suppressed because it is too large Load diff

View file

@ -135,7 +135,8 @@
VAR_EXTENDED_STATISTICS = 351,
VAR_LOCAL_DATA_PTR = 352,
VAR_JOSTLE_TIMEOUT = 353,
VAR_STUB_PRIME = 354
VAR_STUB_PRIME = 354,
VAR_UNWANTED_REPLY_THRESHOLD = 355
};
#endif
/* Tokens. */
@ -236,6 +237,7 @@
#define VAR_LOCAL_DATA_PTR 352
#define VAR_JOSTLE_TIMEOUT 353
#define VAR_STUB_PRIME 354
#define VAR_UNWANTED_REPLY_THRESHOLD 355
@ -247,7 +249,7 @@ typedef union YYSTYPE
char* str;
}
/* Line 1489 of yacc.c. */
#line 251 "util/configparser.h"
#line 253 "util/configparser.h"
YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1

View file

@ -96,7 +96,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_CONTROL_INTERFACE VAR_CONTROL_PORT VAR_SERVER_KEY_FILE
%token VAR_SERVER_CERT_FILE VAR_CONTROL_KEY_FILE VAR_CONTROL_CERT_FILE
%token VAR_EXTENDED_STATISTICS VAR_LOCAL_DATA_PTR VAR_JOSTLE_TIMEOUT
%token VAR_STUB_PRIME
%token VAR_STUB_PRIME VAR_UNWANTED_REPLY_THRESHOLD
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -142,7 +142,8 @@ content_server: server_num_threads | server_verbosity | server_port |
server_dlv_anchor_file | server_dlv_anchor | server_neg_cache_size |
server_harden_referral_path | server_private_address |
server_private_domain | server_extended_statistics |
server_local_data_ptr | server_jostle_timeout
server_local_data_ptr | server_jostle_timeout |
server_unwanted_reply_threshold
;
stubstart: VAR_STUB_ZONE
{
@ -686,6 +687,15 @@ server_private_domain: VAR_PRIVATE_DOMAIN STRING
yyerror("out of memory");
}
;
server_unwanted_reply_threshold: VAR_UNWANTED_REPLY_THRESHOLD STRING
{
OUTYY(("P(server_unwanted_reply_threshold:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->unwanted_threshold = atoi($2);
free($2);
}
;
server_do_not_query_address: VAR_DO_NOT_QUERY_ADDRESS STRING
{
OUTYY(("P(server_do_not_query_address:%s)\n", $2));