Add --dnssec-limits option.
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
parent
c3bc0f9972
commit
fbc5713104
|
@ -22,10 +22,10 @@
|
|||
#define EDNS_PKTSZ 1232 /* default max EDNS.0 UDP packet from from /dnsflagday.net/2020 */
|
||||
#define SAFE_PKTSZ 1232 /* "go anywhere" UDP packet size, see https://dnsflagday.net/2020/ */
|
||||
#define KEYBLOCK_LEN 40 /* choose to minimise fragmentation when storing DNSSEC keys */
|
||||
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */
|
||||
#define LIMIT_SIG_FAIL 20 /* Number of signature that can fail to validate in one answer */
|
||||
#define LIMIT_CRYPTO 200 /* max no. of crypto operations to validate one query. */
|
||||
#define LIMIT_NSEC3_ITERS 150 /* Max. number if iterations allowed in NSEC3 record. */
|
||||
#define DNSSEC_LIMIT_WORK 40 /* Max number of queries to validate one question */
|
||||
#define DNSSEC_LIMIT_SIG_FAIL 20 /* Number of signature that can fail to validate in one answer */
|
||||
#define DNSSEC_LIMIT_CRYPTO 200 /* max no. of crypto operations to validate one query. */
|
||||
#define DNSSEC_LIMIT_NSEC3_ITERS 150 /* Max. number if iterations allowed in NSEC3 record. */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define SMALL_PORT_RANGE 30 /* If DNS port range is smaller than this, use different allocation. */
|
||||
#define FORWARD_TEST 1000 /* try all servers every 1000 queries */
|
||||
|
|
|
@ -840,6 +840,12 @@ struct frec {
|
|||
#define LEASE_HAVE_HWADDR 128 /* Have set hwaddress */
|
||||
#define LEASE_EXP_CHANGED 256 /* Lease expiry time changed */
|
||||
|
||||
#define LIMIT_SIG_FAIL 0
|
||||
#define LIMIT_CRYPTO 1
|
||||
#define LIMIT_WORK 2
|
||||
#define LIMIT_NSEC3_ITERS 3
|
||||
#define LIMIT_MAX 4
|
||||
|
||||
struct dhcp_lease {
|
||||
int clid_len; /* length of client identifier */
|
||||
unsigned char *clid; /* clientid */
|
||||
|
@ -1249,7 +1255,7 @@ extern struct daemon {
|
|||
int rr_status_sz;
|
||||
int dnssec_no_time_check;
|
||||
int back_to_the_future;
|
||||
int limit_sig_fail, limit_crypto, limit_work, limit_nsec3_iters;
|
||||
int limit[LIMIT_MAX];
|
||||
#endif
|
||||
struct frec *frec_list;
|
||||
struct frec_src *free_frec_src;
|
||||
|
|
|
@ -479,7 +479,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
|||
rrsetidx = sort_rrset(header, plen, rr_desc, rrsetidx, rrset, daemon->workspacename, keyname);
|
||||
|
||||
/* Now try all the sigs to try and find one which validates */
|
||||
for (sig_fail_cnt = daemon->limit_sig_fail, j = 0; j <sigidx; j++)
|
||||
for (sig_fail_cnt = daemon->limit[LIMIT_SIG_FAIL], j = 0; j <sigidx; j++)
|
||||
{
|
||||
unsigned char *psav, *sig, *digest;
|
||||
int i, wire_len, sig_len;
|
||||
|
@ -692,8 +692,8 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
|||
/* An attacker can waste a lot of our CPU by setting up a giant DNSKEY RRSET full of failing
|
||||
keys, all of which we have to try. Since many failing keys is not likely for
|
||||
a legitimate domain, set a limit on how many can fail. */
|
||||
if ((daemon->limit_sig_fail - (sig_fail_cnt + 1)) > (int)daemon->metrics[METRIC_SIG_FAIL_HWM])
|
||||
daemon->metrics[METRIC_SIG_FAIL_HWM] = daemon->limit_sig_fail - (sig_fail_cnt + 1);
|
||||
if ((daemon->limit[LIMIT_SIG_FAIL] - (sig_fail_cnt + 1)) > (int)daemon->metrics[METRIC_SIG_FAIL_HWM])
|
||||
daemon->metrics[METRIC_SIG_FAIL_HWM] = daemon->limit[LIMIT_SIG_FAIL] - (sig_fail_cnt + 1);
|
||||
if (dec_counter(&sig_fail_cnt, _("per-RRSet signature fails")))
|
||||
return STAT_ABANDONED;
|
||||
}
|
||||
|
@ -1532,7 +1532,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
|||
|
||||
GETSHORT (iterations, p);
|
||||
/* Upper-bound iterations, to avoid DoS. RFC 9276 refers. */
|
||||
if (iterations > daemon->limit_nsec3_iters)
|
||||
if (iterations > daemon->limit[LIMIT_NSEC3_ITERS])
|
||||
return DNSSEC_FAIL_NSEC3_ITERS;
|
||||
|
||||
salt_len = *p++;
|
||||
|
|
|
@ -344,8 +344,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||
if (ad_reqd)
|
||||
forward->flags |= FREC_AD_QUESTION;
|
||||
#ifdef HAVE_DNSSEC
|
||||
forward->work_counter = daemon->limit_work;
|
||||
forward->validate_counter = daemon->limit_crypto;
|
||||
forward->work_counter = daemon->limit[LIMIT_WORK];
|
||||
forward->validate_counter = daemon->limit[LIMIT_CRYPTO];
|
||||
if (do_bit)
|
||||
forward->flags |= FREC_DO_QUESTION;
|
||||
#endif
|
||||
|
@ -1404,11 +1404,11 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
|
|||
}
|
||||
}
|
||||
|
||||
if ((daemon->limit_crypto - forward->validate_counter) > (int)daemon->metrics[METRIC_CRYPTO_HWM])
|
||||
daemon->metrics[METRIC_CRYPTO_HWM] = daemon->limit_crypto - forward->validate_counter;
|
||||
if ((daemon->limit[LIMIT_CRYPTO] - forward->validate_counter) > (int)daemon->metrics[METRIC_CRYPTO_HWM])
|
||||
daemon->metrics[METRIC_CRYPTO_HWM] = daemon->limit[LIMIT_CRYPTO] - forward->validate_counter;
|
||||
|
||||
if ((daemon->limit_work - forward->work_counter) > (int)daemon->metrics[METRIC_WORK_HWM])
|
||||
daemon->metrics[METRIC_WORK_HWM] = daemon->limit_work - forward->work_counter;
|
||||
if ((daemon->limit[LIMIT_WORK] - forward->work_counter) > (int)daemon->metrics[METRIC_WORK_HWM])
|
||||
daemon->metrics[METRIC_WORK_HWM] = daemon->limit[LIMIT_WORK] - forward->work_counter;
|
||||
#endif
|
||||
|
||||
if (option_bool(OPT_NO_REBIND))
|
||||
|
@ -2554,8 +2554,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (master->flags & SERV_DO_DNSSEC))
|
||||
{
|
||||
int keycount = daemon->limit_work; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
|
||||
int validatecount = daemon->limit_crypto;
|
||||
int keycount = daemon->limit[LIMIT_WORK]; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
|
||||
int validatecount = daemon->limit[LIMIT_CRYPTO];
|
||||
int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
|
||||
serv, have_mark, mark, &keycount, &validatecount);
|
||||
char *result, *domain = "result";
|
||||
|
@ -2584,11 +2584,11 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||
|
||||
log_query(F_SECSTAT, domain, &a, result, 0);
|
||||
|
||||
if ((daemon->limit_crypto - validatecount) > (int)daemon->metrics[METRIC_CRYPTO_HWM])
|
||||
daemon->metrics[METRIC_CRYPTO_HWM] = daemon->limit_crypto - validatecount;
|
||||
if ((daemon->limit[LIMIT_CRYPTO] - validatecount) > (int)daemon->metrics[METRIC_CRYPTO_HWM])
|
||||
daemon->metrics[METRIC_CRYPTO_HWM] = daemon->limit[LIMIT_CRYPTO] - validatecount;
|
||||
|
||||
if ((daemon->limit_work - keycount) > (int)daemon->metrics[METRIC_WORK_HWM])
|
||||
daemon->metrics[METRIC_WORK_HWM] = daemon->limit_work - keycount;
|
||||
if ((daemon->limit[LIMIT_WORK] - keycount) > (int)daemon->metrics[METRIC_WORK_HWM])
|
||||
daemon->metrics[METRIC_WORK_HWM] = daemon->limit[LIMIT_WORK] - keycount;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -195,6 +195,7 @@ struct myoption {
|
|||
#define LOPT_NO_DHCP6 382
|
||||
#define LOPT_NO_DHCP4 383
|
||||
#define LOPT_MAX_PROCS 384
|
||||
#define LOPT_DNSSEC_LIMITS 385
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
|
@ -368,6 +369,7 @@ static const struct myoption opts[] =
|
|||
{ "dnssec-check-unsigned", 2, 0, LOPT_DNSSEC_CHECK },
|
||||
{ "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
|
||||
{ "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
|
||||
{ "dnssec-limits", 1, 0, LOPT_DNSSEC_LIMITS },
|
||||
{ "dhcp-relay", 1, 0, LOPT_RELAY },
|
||||
{ "ra-param", 1, 0, LOPT_RA_PARAM },
|
||||
{ "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },
|
||||
|
@ -572,6 +574,7 @@ static struct {
|
|||
{ LOPT_DNSSEC_CHECK, ARG_DUP, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
|
||||
{ LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
|
||||
{ LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
|
||||
{ LOPT_DNSSEC_LIMITS, ARG_ONE, "<limit>,..", gettext_noop("Set resource limits for DNSSEC validation"), NULL },
|
||||
{ LOPT_RA_PARAM, ARG_DUP, "<iface>,[mtu:<value>|<interface>|off,][<prio>,]<intval>[,<lifetime>]", gettext_noop("Set MTU, priority, resend-interval and router-lifetime"), NULL },
|
||||
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
|
||||
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
|
||||
|
@ -5262,6 +5265,24 @@ err:
|
|||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
case LOPT_DNSSEC_LIMITS:
|
||||
{
|
||||
int lim, val;
|
||||
|
||||
for (lim = LIMIT_SIG_FAIL; arg && lim < LIMIT_MAX ; lim++, arg = comma)
|
||||
{
|
||||
comma = split(arg);
|
||||
|
||||
if (!atoi_check(arg, &val))
|
||||
ret_err(gen_err);
|
||||
|
||||
if (val != 0)
|
||||
daemon->limit[lim] = val;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LOPT_DNSSEC_STAMP: /* --dnssec-timestamp */
|
||||
daemon->timestamp_file = opt_string_alloc(arg);
|
||||
break;
|
||||
|
@ -5874,10 +5895,10 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
|||
daemon->host_index = SRC_AH;
|
||||
daemon->max_procs = MAX_PROCS;
|
||||
#ifdef HAVE_DNSSEC
|
||||
daemon->limit_sig_fail = LIMIT_SIG_FAIL;
|
||||
daemon->limit_crypto = LIMIT_CRYPTO;
|
||||
daemon->limit_work = DNSSEC_WORK;
|
||||
daemon->limit_nsec3_iters = LIMIT_NSEC3_ITERS;
|
||||
daemon->limit[LIMIT_SIG_FAIL] = DNSSEC_LIMIT_SIG_FAIL;
|
||||
daemon->limit[LIMIT_CRYPTO] = DNSSEC_LIMIT_CRYPTO;
|
||||
daemon->limit[LIMIT_WORK] = DNSSEC_LIMIT_WORK;
|
||||
daemon->limit[LIMIT_NSEC3_ITERS] = DNSSEC_LIMIT_NSEC3_ITERS;
|
||||
#endif
|
||||
|
||||
/* See comment above make_servers(). Optimises server-read code. */
|
||||
|
|
Loading…
Reference in New Issue