Make VAL_MAX_RESTART_COUNT configurable.

unbound tries very hard (up to 6 authoritative servers) to find a
validating answer. This is not always desirable, for example on high
latency links.
This commit is contained in:
Florian Obser 2021-05-08 16:56:32 +02:00
parent e217bb48ad
commit d4314cad33
7 changed files with 50 additions and 22 deletions

View file

@ -1131,6 +1131,10 @@ min and max very low disables the clock skew allowances. Setting both
min and max very high makes the validator check the signature timestamps
less strictly.
.TP
.B val\-max\-restart: \fI<number>
The maximum number the validator should restart validation with
another authority in case of failed validation. Default is 5.
.TP
.B val\-bogus\-ttl: \fI<number>
The time to live for bogus data. This is data that has failed validation;
due to invalid signatures or other checks. The TTL from that data cannot be

View file

@ -253,6 +253,7 @@ config_create(void)
cfg->val_date_override = 0;
cfg->val_sig_skew_min = 3600; /* at least daylight savings trouble */
cfg->val_sig_skew_max = 86400; /* at most timezone settings trouble */
cfg->val_max_restart = 5;
cfg->val_clean_additional = 1;
cfg->val_log_level = 0;
cfg->val_log_squelch = 0;
@ -764,12 +765,14 @@ int config_set_option(struct config_file* cfg, const char* opt,
#endif
else if(strcmp(opt, "define-tag:") ==0) {
return config_add_tag(cfg, val);
/* val_sig_skew_min and max are copied into val_env during init,
* so this does not update val_env with set_option */
/* val_sig_skew_min, max and val_max_restart are copied into val_env
* during init so this does not update val_env with set_option */
} else if(strcmp(opt, "val-sig-skew-min:") == 0)
{ IS_NUMBER_OR_ZERO; cfg->val_sig_skew_min = (int32_t)atoi(val); }
else if(strcmp(opt, "val-sig-skew-max:") == 0)
{ IS_NUMBER_OR_ZERO; cfg->val_sig_skew_max = (int32_t)atoi(val); }
else if(strcmp(opt, "val-max-restart:") == 0)
{ IS_NUMBER_OR_ZERO; cfg->val_max_restart = (int32_t)atoi(val); }
else if (strcmp(opt, "outgoing-interface:") == 0) {
char* d = strdup(val);
char** oi =
@ -1190,6 +1193,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_DEC(opt, "fast-server-permil", fast_server_permil)
else O_DEC(opt, "val-sig-skew-min", val_sig_skew_min)
else O_DEC(opt, "val-sig-skew-max", val_sig_skew_max)
else O_DEC(opt, "val-max-restart", val_max_restart)
else O_YNO(opt, "qname-minimisation", qname_minimisation)
else O_YNO(opt, "qname-minimisation-strict", qname_minimisation_strict)
else O_IFC(opt, "define-tag", num_tags, tagname)

View file

@ -373,6 +373,8 @@ struct config_file {
int32_t val_sig_skew_min;
/** the maximum for signature clock skew */
int32_t val_sig_skew_max;
/** max number of query restarts, number of IPs to probe */
int32_t val_max_restart;
/** this value sets the number of seconds before revalidating bogus */
int bogus_ttl;
/** should validator clean additional section for secure msgs */

View file

@ -385,6 +385,7 @@ root-key-sentinel{COLON} { YDVAR(1, VAR_ROOT_KEY_SENTINEL) }
val-override-date{COLON} { YDVAR(1, VAR_VAL_OVERRIDE_DATE) }
val-sig-skew-min{COLON} { YDVAR(1, VAR_VAL_SIG_SKEW_MIN) }
val-sig-skew-max{COLON} { YDVAR(1, VAR_VAL_SIG_SKEW_MAX) }
val-max-restart{COLON} { YDVAR(1, VAR_VAL_MAX_RESTART) }
val-bogus-ttl{COLON} { YDVAR(1, VAR_BOGUS_TTL) }
val-clean-additional{COLON} { YDVAR(1, VAR_VAL_CLEAN_ADDITIONAL) }
val-permissive-mode{COLON} { YDVAR(1, VAR_VAL_PERMISSIVE_MODE) }

View file

@ -104,13 +104,14 @@ extern struct config_parser_state* cfg_parser;
%token VAR_EXTENDED_STATISTICS VAR_LOCAL_DATA_PTR VAR_JOSTLE_TIMEOUT
%token VAR_STUB_PRIME VAR_UNWANTED_REPLY_THRESHOLD VAR_LOG_TIME_ASCII
%token VAR_DOMAIN_INSECURE VAR_PYTHON VAR_PYTHON_SCRIPT VAR_VAL_SIG_SKEW_MIN
%token VAR_VAL_SIG_SKEW_MAX VAR_CACHE_MIN_TTL VAR_VAL_LOG_LEVEL
%token VAR_AUTO_TRUST_ANCHOR_FILE VAR_KEEP_MISSING VAR_ADD_HOLDDOWN
%token VAR_DEL_HOLDDOWN VAR_SO_RCVBUF VAR_EDNS_BUFFER_SIZE VAR_PREFETCH
%token VAR_PREFETCH_KEY VAR_SO_SNDBUF VAR_SO_REUSEPORT VAR_HARDEN_BELOW_NXDOMAIN
%token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_LOG_REPLIES VAR_LOG_LOCAL_ACTIONS
%token VAR_TCP_UPSTREAM VAR_SSL_UPSTREAM VAR_TCP_AUTH_QUERY_TIMEOUT
%token VAR_SSL_SERVICE_KEY VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST
%token VAR_VAL_SIG_SKEW_MAX VAR_VAL_MAX_RESTART VAR_CACHE_MIN_TTL
%token VAR_VAL_LOG_LEVEL VAR_AUTO_TRUST_ANCHOR_FILE VAR_KEEP_MISSING
%token VAR_ADD_HOLDDOWN VAR_DEL_HOLDDOWN VAR_SO_RCVBUF VAR_EDNS_BUFFER_SIZE
%token VAR_PREFETCH VAR_PREFETCH_KEY VAR_SO_SNDBUF VAR_SO_REUSEPORT
%token VAR_HARDEN_BELOW_NXDOMAIN VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES
%token VAR_LOG_REPLIES VAR_LOG_LOCAL_ACTIONS VAR_TCP_UPSTREAM
%token VAR_SSL_UPSTREAM VAR_TCP_AUTH_QUERY_TIMEOUT VAR_SSL_SERVICE_KEY
%token VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST
%token VAR_STUB_SSL_UPSTREAM VAR_FORWARD_SSL_UPSTREAM VAR_TLS_CERT_BUNDLE
%token VAR_HTTPS_PORT VAR_HTTP_ENDPOINT VAR_HTTP_MAX_STREAMS
%token VAR_HTTP_QUERY_BUFFER_SIZE VAR_HTTP_RESPONSE_BUFFER_SIZE
@ -243,8 +244,9 @@ content_server: server_num_threads | server_verbosity | server_port |
server_local_data_ptr | server_jostle_timeout |
server_unwanted_reply_threshold | server_log_time_ascii |
server_domain_insecure | server_val_sig_skew_min |
server_val_sig_skew_max | server_cache_min_ttl | server_val_log_level |
server_auto_trust_anchor_file | server_add_holddown |
server_val_sig_skew_max | server_val_max_restart |
server_cache_min_ttl | server_val_log_level |
server_auto_trust_anchor_file | server_add_holddown |
server_del_holddown | server_keep_missing | server_so_rcvbuf |
server_edns_buffer_size | server_prefetch | server_prefetch_key |
server_so_sndbuf | server_harden_below_nxdomain | server_ignore_cd_flag |
@ -1852,6 +1854,19 @@ server_val_sig_skew_max: VAR_VAL_SIG_SKEW_MAX STRING_ARG
free($2);
}
;
server_val_max_restart: VAR_VAL_MAX_RESTART STRING_ARG
{
OUTYY(("P(server_val_max_restart:%s)\n", $2));
if(*$2 == '\0' || strcmp($2, "0") == 0) {
cfg_parser->cfg->val_max_restart = 0;
} else {
cfg_parser->cfg->val_max_restart = atoi($2);
if(!cfg_parser->cfg->val_max_restart)
yyerror("number expected");
}
free($2);
}
;
server_cache_max_ttl: VAR_CACHE_MAX_TTL STRING_ARG
{
OUTYY(("P(server_cache_max_ttl:%s)\n", $2));

View file

@ -137,6 +137,7 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env,
val_env->date_override = cfg->val_date_override;
val_env->skew_min = cfg->val_sig_skew_min;
val_env->skew_max = cfg->val_sig_skew_max;
val_env->max_restart = cfg->val_max_restart;
c = cfg_count_numbers(cfg->val_nsec3_key_iterations);
if(c < 1 || (c&1)) {
log_err("validator: unparseable or odd nsec3 key "
@ -1487,7 +1488,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
enum val_classification subtype = val_classify_response(
qstate->query_flags, &qstate->qinfo, &vq->qchase,
vq->orig_msg->rep, vq->rrset_skip);
if(vq->restart_count > VAL_MAX_RESTART_COUNT) {
if(vq->restart_count > ve->max_restart) {
verbose(VERB_ALGO, "restart count exceeded");
return val_error(qstate, id);
}
@ -1640,7 +1641,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
errinf(qstate, key_entry_get_reason(vq->key_entry));
}
/* no retries, stop bothering the authority until timeout */
vq->restart_count = VAL_MAX_RESTART_COUNT;
vq->restart_count = ve->max_restart;
vq->chase_reply->security = sec_status_bogus;
vq->state = VAL_FINISHED_STATE;
return 1;
@ -1848,7 +1849,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
LDNS_RR_TYPE_DNSKEY, vq->key_entry->key_class);
vq->chase_reply->security = sec_status_bogus;
errinf(qstate, "while building chain of trust");
if(vq->restart_count >= VAL_MAX_RESTART_COUNT)
if(vq->restart_count >= ve->max_restart)
key_cache_insert(ve->kcache, vq->key_entry, qstate);
return 1;
}
@ -2064,7 +2065,7 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
* endless bogus revalidation */
if(vq->orig_msg->rep->security == sec_status_bogus) {
/* see if we can try again to fetch data */
if(vq->restart_count < VAL_MAX_RESTART_COUNT) {
if(vq->restart_count < ve->max_restart) {
int restart_count = vq->restart_count+1;
verbose(VERB_ALGO, "validation failed, "
"blacklist and retry to fetch data");
@ -2605,6 +2606,7 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
struct sock_list* origin)
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
struct key_entry_key* dske = NULL;
uint8_t* olds = vq->empty_DS_name;
vq->empty_DS_name = NULL;
@ -2638,7 +2640,7 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
vq->chain_blacklist = NULL; /* fresh blacklist for next part*/
/* Keep the forState.state on FINDKEY. */
} else if(key_entry_isbad(dske)
&& vq->restart_count < VAL_MAX_RESTART_COUNT) {
&& vq->restart_count < ve->max_restart) {
vq->empty_DS_name = olds;
val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1);
qstate->errinf = NULL;
@ -2691,7 +2693,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
/* bad response */
verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to "
"DNSKEY query.");
if(vq->restart_count < VAL_MAX_RESTART_COUNT) {
if(vq->restart_count < ve->max_restart) {
val_blacklist(&vq->chain_blacklist, qstate->region,
origin, 1);
qstate->errinf = NULL;
@ -2730,7 +2732,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
* state. */
if(!key_entry_isgood(vq->key_entry)) {
if(key_entry_isbad(vq->key_entry)) {
if(vq->restart_count < VAL_MAX_RESTART_COUNT) {
if(vq->restart_count < ve->max_restart) {
val_blacklist(&vq->chain_blacklist,
qstate->region, origin, 1);
qstate->errinf = NULL;
@ -2807,7 +2809,7 @@ process_prime_response(struct module_qstate* qstate, struct val_qstate* vq,
lock_basic_unlock(&ta->lock);
if(vq->key_entry) {
if(key_entry_isbad(vq->key_entry)
&& vq->restart_count < VAL_MAX_RESTART_COUNT) {
&& vq->restart_count < ve->max_restart) {
val_blacklist(&vq->chain_blacklist, qstate->region,
origin, 1);
qstate->errinf = NULL;

View file

@ -64,9 +64,6 @@ struct config_strlist;
*/
#define BOGUS_KEY_TTL 60 /* seconds */
/** max number of query restarts, number of IPs to probe */
#define VAL_MAX_RESTART_COUNT 5
/** Root key sentinel is ta preamble */
#define SENTINEL_IS "root-key-sentinel-is-ta-"
/** Root key sentinel is not ta preamble */
@ -95,6 +92,9 @@ struct val_env {
/** clock skew max for signatures */
int32_t skew_max;
/** max number of query restarts, number of IPs to probe */
int32_t max_restart;
/** TTL for bogus data; used instead of untrusted TTL from data.
* Bogus data will not be verified more often than this interval.
* seconds. */