- Add iter-scrub-ns, iter-scrub-cname and max-global-quota

configuration options.
This commit is contained in:
W.C.A. Wijngaards 2024-08-20 14:08:52 +02:00
parent 015b2b0daf
commit 3d350fa73d
11 changed files with 2326 additions and 10 deletions

View File

@ -1,3 +1,7 @@
20 August 2024: Wouter
- Add iter-scrub-ns, iter-scrub-cname and max-global-quota
configuration options.
19 August 2024: Wouter
- Fix #1126: unbound-control-setup hangs while testing for openssl
presence starting from version 1.21.0.

View File

@ -187,6 +187,15 @@ server:
# query upon encountering a CNAME record.
# max-query-restarts: 11
# Limit on number of NS records in NS RRset for incoming packets.
# iter-scrub-ns: 20
# Limit on number of CNAME, DNAME records for incoming packets.
# iter-scrub-cname: 11
# Limit on upstream queries for an incoming query and its recursion.
# max-global-quota: 128
# msec for waiting for an unknown server to reply. Increase if you
# are behind a slow satellite link, to eg. 1128.
# unknown-server-time-limit: 376

View File

@ -1957,6 +1957,23 @@ Changing this value needs caution as it can allow long CNAME chains to be
accepted, where Unbound needs to verify (resolve) each link individually.
Default is 11.
.TP 5
.B iter\-scrub\-ns: \fI<number>
Limit on the number of NS records allowed in an rrset of type NS, from the
iterator scrubber. This protects the internals of the resolver from overly
large NS sets. Default is 20.
.TP 5
.B iter\-scrub\-cname: \fI<number>
Limit on the number of CNAME, DNAME records in an answer, from the iterator
scrubber. This protects the internals of the resolver from overly long
indirection chains. Clips off the remainder of the reply packet at that point.
Default is 11.
.TP 5
.B max\-global\-quota: \fI<number>
Limit on the number of upstream queries sent out for an incoming query and
its subqueries from recursion. It is not reset during the resolution. When
it is exceeded the query is failed and the lookup process stops.
Default is 128.
.TP 5
.B fast\-server\-permil: \fI<number>
Specify how many times out of 1000 to pick from the set of fastest servers.
0 turns the feature off. A value of 900 would pick from the fastest

View File

@ -443,7 +443,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
prev = NULL;
rrset = msg->rrset_first;
while(rrset && rrset->section == LDNS_SECTION_ANSWER) {
if(cname_length > 11 /* env->cfg.iter_scrub_cname */) {
if(cname_length > env->cfg->iter_scrub_cname) {
/* Too many CNAMEs, or DNAMEs, from the authority
* server, scrub down the length to something
* shorter. This deletes everything after the limit
@ -562,8 +562,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
dname_pkt_compare(pkt, oldsname,
rrset->dname) == 0) {
if(rrset->type == LDNS_RR_TYPE_NS &&
rrset->rr_count > 20 /* env->cfg->iter_scrub_ns */) {
shorten_rrset(pkt, rrset, 20 /* env->cfg->iter_scrub_ns */);
rrset->rr_count > env->cfg->iter_scrub_ns) {
shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
}
prev = rrset;
rrset = rrset->rrset_all_next;
@ -581,8 +581,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
}
if(rrset->type == LDNS_RR_TYPE_NS &&
rrset->rr_count > 20 /* env->cfg->iter_scrub_ns */) {
shorten_rrset(pkt, rrset, 20 /* env->cfg->iter_scrub_ns */);
rrset->rr_count > env->cfg->iter_scrub_ns) {
shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
}
/* Mark the additional names from relevant rrset as OK. */
@ -641,7 +641,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
"RRset:", pkt, msg, prev, &rrset);
continue;
}
if(rrset->rr_count > 20 /* env->cfg->iter_scrub_ns */) {
if(rrset->rr_count > env->cfg->iter_scrub_ns) {
/* If this is not a referral, and the NS RRset
* is signed, then remove it entirely, so
* that when it becomes bogus it does not
@ -657,7 +657,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
"RRset:", pkt, msg, prev, &rrset);
continue;
} else {
shorten_rrset(pkt, rrset, 20 /* env->cfg->iter_scrub_ns */);
shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
}
}
}

View File

@ -70,6 +70,8 @@
#include "sldns/parseutil.h"
#include "sldns/sbuffer.h"
/* number of packets */
int MAX_GLOBAL_QUOTA = 128;
/* in msec */
int UNKNOWN_SERVER_NICENESS = 376;
/* in msec */

View File

@ -57,7 +57,7 @@ struct rbtree_type;
#define MAX_TARGET_COUNT 64
/** max number of upstream queries for a query and its subqueries, it is
* never reset. */
#define MAX_GLOBAL_QUOTA 128
extern int MAX_GLOBAL_QUOTA;
/** max number of target lookups per qstate, per delegation point */
#define MAX_DP_TARGET_COUNT 16
/** max number of nxdomains allowed for target lookups for a query and

2236
testdata/iter_max_global_quota.rpl vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -408,6 +408,9 @@ config_create(void)
cfg->ipset_name_v6 = NULL;
#endif
cfg->ede = 0;
cfg->iter_scrub_ns = 20;
cfg->iter_scrub_cname = 11;
cfg->max_global_quota = 128;
return cfg;
error_exit:
config_delete(cfg);
@ -718,6 +721,9 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_NUMBER_OR_ZERO("serve-expired-client-timeout:", serve_expired_client_timeout)
else S_YNO("ede:", ede)
else S_YNO("ede-serve-expired:", ede_serve_expired)
else S_NUMBER_OR_ZERO("iter-scrub-ns:", iter_scrub_ns)
else S_NUMBER_OR_ZERO("iter-scrub-cname:", iter_scrub_cname)
else S_NUMBER_OR_ZERO("max-global-quota:", max_global_quota)
else S_YNO("serve-original-ttl:", serve_original_ttl)
else S_STR("val-nsec3-keysize-iterations:", val_nsec3_key_iterations)
else S_YNO("zonemd-permissive-mode:", zonemd_permissive_mode)
@ -1186,6 +1192,9 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_DEC(opt, "serve-expired-client-timeout", serve_expired_client_timeout)
else O_YNO(opt, "ede", ede)
else O_YNO(opt, "ede-serve-expired", ede_serve_expired)
else O_DEC(opt, "iter-scrub-ns", iter_scrub_ns)
else O_DEC(opt, "iter-scrub-cname", iter_scrub_cname)
else O_DEC(opt, "max-global-quota", max_global_quota)
else O_YNO(opt, "serve-original-ttl", serve_original_ttl)
else O_STR(opt, "val-nsec3-keysize-iterations",val_nsec3_key_iterations)
else O_YNO(opt, "zonemd-permissive-mode", zonemd_permissive_mode)
@ -2389,6 +2398,7 @@ config_apply(struct config_file* config)
MINIMAL_RESPONSES = config->minimal_responses;
RRSET_ROUNDROBIN = config->rrset_roundrobin;
LOG_TAG_QUERYREPLY = config->log_tag_queryreply;
MAX_GLOBAL_QUOTA = config->max_global_quota;
UNKNOWN_SERVER_NICENESS = config->unknown_server_time_limit;
USEFUL_SERVER_TOP_TIMEOUT = RTT_MAX_TIMEOUT;
BLACKLIST_PENALTY = USEFUL_SERVER_TOP_TIMEOUT*4;

View File

@ -760,6 +760,12 @@ struct config_file {
#endif
/** respond with Extended DNS Errors (RFC8914) */
int ede;
/** limit on NS RRs in RRset for the iterator scrubber. */
size_t iter_scrub_ns;
/** limit on CNAME, DNAME RRs in answer for the iterator scrubber. */
int iter_scrub_cname;
/** limit on upstream queries for an incoming query and subqueries. */
int max_global_quota;
};
/** from cfg username, after daemonize setup performed */

View File

@ -588,6 +588,9 @@ edns-client-string-opcode{COLON} { YDVAR(1, VAR_EDNS_CLIENT_STRING_OPCODE) }
nsid{COLON} { YDVAR(1, VAR_NSID ) }
ede{COLON} { YDVAR(1, VAR_EDE ) }
proxy-protocol-port{COLON} { YDVAR(1, VAR_PROXY_PROTOCOL_PORT) }
iter-scrub-ns{COLON} { YDVAR(1, VAR_ITER_SCRUB_NS) }
iter-scrub-cname{COLON} { YDVAR(1, VAR_ITER_SCRUB_CNAME) }
max-global-quota{COLON} { YDVAR(1, VAR_MAX_GLOBAL_QUOTA) }
<INITIAL,val>{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; }
/* Quoted strings. Strip leading and ending quotes */

View File

@ -205,7 +205,8 @@ extern struct config_parser_state* cfg_parser;
%token VAR_PROXY_PROTOCOL_PORT VAR_STATISTICS_INHIBIT_ZERO
%token VAR_HARDEN_UNKNOWN_ADDITIONAL VAR_DISABLE_EDNS_DO VAR_CACHEDB_NO_STORE
%token VAR_LOG_DESTADDR VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED
%token VAR_COOKIE_SECRET_FILE
%token VAR_COOKIE_SECRET_FILE VAR_ITER_SCRUB_NS VAR_ITER_SCRUB_CNAME
%token VAR_MAX_GLOBAL_QUOTA
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -343,7 +344,8 @@ content_server: server_num_threads | server_verbosity | server_port |
server_interface_automatic_ports | server_ede |
server_proxy_protocol_port | server_statistics_inhibit_zero |
server_harden_unknown_additional | server_disable_edns_do |
server_log_destaddr | server_cookie_secret_file
server_log_destaddr | server_cookie_secret_file |
server_iter_scrub_ns | server_iter_scrub_cname | server_max_global_quota
;
stubstart: VAR_STUB_ZONE
{
@ -4006,6 +4008,33 @@ server_cookie_secret_file: VAR_COOKIE_SECRET_FILE STRING_ARG
cfg_parser->cfg->cookie_secret_file = $2;
}
;
server_iter_scrub_ns: VAR_ITER_SCRUB_NS STRING_ARG
{
OUTYY(("P(server_iter_scrub_ns:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->iter_scrub_ns = atoi($2);
free($2);
}
;
server_iter_scrub_cname: VAR_ITER_SCRUB_CNAME STRING_ARG
{
OUTYY(("P(server_iter_scrub_cname:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->iter_scrub_cname = atoi($2);
free($2);
}
;
server_max_global_quota: VAR_MAX_GLOBAL_QUOTA STRING_ARG
{
OUTYY(("P(server_max_global_quota:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->max_global_quota = atoi($2);
free($2);
}
;
ipsetstart: VAR_IPSET
{
OUTYY(("\nP(ipset:)\n"));