mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-09-21 17:27:46 +02:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13b6717f17 | ||
|
|
0d4a6a63dd | ||
|
|
bd71e3b8a6 | ||
|
|
3a6ba0da81 | ||
|
|
3d65973d38 | ||
|
|
565651cd02 | ||
|
|
7914901915 | ||
|
|
eba3d35ad4 | ||
|
|
8c2e0fd6cc | ||
|
|
e619ead2db | ||
|
|
eb86d9bc50 |
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.71 for unbound 1.26.0.
|
||||
# Generated by GNU Autoconf 2.71 for unbound 1.26.1.
|
||||
#
|
||||
# Report bugs to <unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues>.
|
||||
#
|
||||
@@ -622,8 +622,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='unbound'
|
||||
PACKAGE_TARNAME='unbound'
|
||||
PACKAGE_VERSION='1.26.0'
|
||||
PACKAGE_STRING='unbound 1.26.0'
|
||||
PACKAGE_VERSION='1.26.1'
|
||||
PACKAGE_STRING='unbound 1.26.1'
|
||||
PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues'
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -1513,7 +1513,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures unbound 1.26.0 to adapt to many kinds of systems.
|
||||
\`configure' configures unbound 1.26.1 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1579,7 +1579,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of unbound 1.26.0:";;
|
||||
short | recursive ) echo "Configuration of unbound 1.26.1:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1832,7 +1832,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
unbound configure 1.26.0
|
||||
unbound configure 1.26.1
|
||||
generated by GNU Autoconf 2.71
|
||||
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
@@ -2489,7 +2489,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by unbound $as_me 1.26.0, which was
|
||||
It was created by unbound $as_me 1.26.1, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
$ $0$ac_configure_args_raw
|
||||
@@ -3253,11 +3253,11 @@ UNBOUND_VERSION_MAJOR=1
|
||||
|
||||
UNBOUND_VERSION_MINOR=26
|
||||
|
||||
UNBOUND_VERSION_MICRO=0
|
||||
UNBOUND_VERSION_MICRO=1
|
||||
|
||||
|
||||
LIBUNBOUND_CURRENT=9
|
||||
LIBUNBOUND_REVISION=39
|
||||
LIBUNBOUND_REVISION=40
|
||||
LIBUNBOUND_AGE=1
|
||||
# 1.0.0 had 0:12:0
|
||||
# 1.0.1 had 0:13:0
|
||||
@@ -3364,6 +3364,7 @@ LIBUNBOUND_AGE=1
|
||||
# 1.25.1 had 9:37:1
|
||||
# 1.25.2 had 9:38:1
|
||||
# 1.26.0 had 9:39:1
|
||||
# 1.26.1 had 9:40:1
|
||||
|
||||
# Current -- the number of the binary API that we're implementing
|
||||
# Revision -- which iteration of the implementation of the binary
|
||||
@@ -25711,7 +25712,7 @@ printf "%s\n" "#define MAXSYSLOGMSGLEN 10240" >>confdefs.h
|
||||
|
||||
|
||||
|
||||
version=1.26.0
|
||||
version=1.26.1
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build time" >&5
|
||||
printf %s "checking for build time... " >&6; }
|
||||
@@ -26241,7 +26242,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by unbound $as_me 1.26.0, which was
|
||||
This file was extended by unbound $as_me 1.26.1, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -26309,7 +26310,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config='$ac_cs_config_escaped'
|
||||
ac_cs_version="\\
|
||||
unbound config.status 1.26.0
|
||||
unbound config.status 1.26.1
|
||||
configured by $0, generated by GNU Autoconf 2.71,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+3
-2
@@ -12,14 +12,14 @@ sinclude(dnscrypt/dnscrypt.m4)
|
||||
# must be numbers. ac_defun because of later processing
|
||||
m4_define([VERSION_MAJOR],[1])
|
||||
m4_define([VERSION_MINOR],[26])
|
||||
m4_define([VERSION_MICRO],[0])
|
||||
m4_define([VERSION_MICRO],[1])
|
||||
AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues],[unbound])
|
||||
AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR])
|
||||
AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR])
|
||||
AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO])
|
||||
|
||||
LIBUNBOUND_CURRENT=9
|
||||
LIBUNBOUND_REVISION=39
|
||||
LIBUNBOUND_REVISION=40
|
||||
LIBUNBOUND_AGE=1
|
||||
# 1.0.0 had 0:12:0
|
||||
# 1.0.1 had 0:13:0
|
||||
@@ -126,6 +126,7 @@ LIBUNBOUND_AGE=1
|
||||
# 1.25.1 had 9:37:1
|
||||
# 1.25.2 had 9:38:1
|
||||
# 1.26.0 had 9:39:1
|
||||
# 1.26.1 had 9:40:1
|
||||
|
||||
# Current -- the number of the binary API that we're implementing
|
||||
# Revision -- which iteration of the implementation of the binary
|
||||
|
||||
@@ -6590,6 +6590,8 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg,
|
||||
COPY_VAR_ptr(ipset_name_v6);
|
||||
#endif
|
||||
COPY_VAR_int(ede);
|
||||
COPY_VAR_int(val_validation_attempts);
|
||||
COPY_VAR_int(val_hash_attempts);
|
||||
COPY_VAR_int(iter_scrub_ns);
|
||||
COPY_VAR_int(iter_scrub_cname);
|
||||
COPY_VAR_int(iter_scrub_rrsig);
|
||||
|
||||
+1
-1
@@ -863,7 +863,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
"validation");
|
||||
goto bail_out; /* need to validate cache entry first */
|
||||
} else if(rep->security == sec_status_secure) {
|
||||
if(reply_all_rrsets_secure(rep)) {
|
||||
if(reply_an_ns_rrsets_secure(rep)) {
|
||||
*is_secure_answer = 1;
|
||||
} else {
|
||||
if(must_validate) {
|
||||
|
||||
+7
-1
@@ -203,6 +203,12 @@ server:
|
||||
# protects against poison attempts.
|
||||
# iter-scrub-promiscuous: yes
|
||||
|
||||
# Limit on number of DNSSEC validation attempts for a query.
|
||||
# val-validation-attempts: 32
|
||||
|
||||
# Limit on number of DNSSEC hash attempts for a query.
|
||||
# val-hash-attempts: 32
|
||||
|
||||
# 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
|
||||
@@ -728,7 +734,7 @@ server:
|
||||
# non-secure data. Useful to shield the users of this validator from
|
||||
# potential bogus data in the additional section. All unsigned data
|
||||
# in the additional section is removed from secure messages.
|
||||
# val-clean-additional: yes
|
||||
# val-clean-additional: no
|
||||
|
||||
# Turn permissive mode on to permit bogus messages. Thus, messages
|
||||
# for which security checks failed will be returned to clients,
|
||||
|
||||
+21
-1
@@ -2320,7 +2320,7 @@ These options are part of the ``server:`` section.
|
||||
Use this setting to protect the users that rely on this validator for
|
||||
authentication from potentially bad data in the additional section.
|
||||
|
||||
Default: yes
|
||||
Default: no
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@val-log-level@@: *<number>*
|
||||
@@ -3358,6 +3358,26 @@ These options are part of the ``server:`` section.
|
||||
Default: yes
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@val-validation-attempts@@: *<number>*
|
||||
Limit on the number of DNSSEC validation attempts for a query.
|
||||
This protects against too large numbers of cryptographic operations,
|
||||
like for a deep delegation chain.
|
||||
This counts attempts to validate RRSIGs.
|
||||
When it is exceeded, the query fails.
|
||||
|
||||
Default: 32
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@val-hash-attempts@@: *<number>*
|
||||
Limit on the number of DNSSEC hash attempts for a query.
|
||||
This protects against too large numbers of cryptographic operations,
|
||||
like for a deep delegation chain.
|
||||
This counts DS hash attempts to match DNSKEYs.
|
||||
When it is exceeded, the query fails.
|
||||
|
||||
Default: 32
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@fast-server-permil@@: *<number>*
|
||||
Specify how many times out of 1000 to pick from the set of fastest servers.
|
||||
0 turns the feature off.
|
||||
|
||||
+19
-1
@@ -294,7 +294,14 @@ synth_cname_rrset(uint8_t** sname, size_t* snamelen, uint8_t* alias,
|
||||
if(ttl_t > MAX_TTL) ttl_t = MAX_TTL;
|
||||
ttl = (uint32_t)ttl_t;
|
||||
sldns_write_uint32(cn->rr_first->ttl_data, ttl);
|
||||
sldns_write_uint32(rrset->rr_first->ttl_data, ttl);
|
||||
/* Do NOT write the clamp back into the packet buffer:
|
||||
* parse_packet already sized every name from the original
|
||||
* bytes and rdata_copy re-walks them trusting those sizes;
|
||||
* mutating packet bytes between the walks breaks that
|
||||
* invariant (compression pointers can target these TTL
|
||||
* bytes). The DNAME rrset receives the same clamp at store
|
||||
* time in rdata_copy, so the DNAME and the synthesized
|
||||
* CNAME still carry equal TTLs in the cache. */
|
||||
}
|
||||
sldns_write_uint16(cn->rr_first->ttl_data+4, aliaslen);
|
||||
memmove(cn->rr_first->ttl_data+6, alias, aliaslen);
|
||||
@@ -648,6 +655,9 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
if(rrset->type == LDNS_RR_TYPE_NS &&
|
||||
rrset->rr_count > env->cfg->iter_scrub_ns) {
|
||||
shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
|
||||
} else if(rrset->type == LDNS_RR_TYPE_DS &&
|
||||
rrset->rr_count > env->cfg->iter_scrub_ns) {
|
||||
shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
|
||||
}
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
@@ -667,6 +677,9 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
if(rrset->type == LDNS_RR_TYPE_NS &&
|
||||
rrset->rr_count > env->cfg->iter_scrub_ns) {
|
||||
shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
|
||||
} else if(rrset->type == LDNS_RR_TYPE_DS &&
|
||||
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. */
|
||||
@@ -791,6 +804,11 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
shorten_rrset(pkt, rrset, env->cfg->iter_scrub_ns);
|
||||
}
|
||||
}
|
||||
} else if(rrset->type==LDNS_RR_TYPE_DS) {
|
||||
if(rrset->rr_count > env->cfg->iter_scrub_ns) {
|
||||
shorten_rrset(pkt, rrset,
|
||||
env->cfg->iter_scrub_ns);
|
||||
}
|
||||
}
|
||||
/* if this is type DS and we query for type DS we just got
|
||||
* a referral answer for our type DS query, fix packet */
|
||||
|
||||
+177
-67
@@ -392,6 +392,20 @@ auth_data_del(rbnode_type* n, void* ATTR_UNUSED(arg))
|
||||
auth_data_delete(z);
|
||||
}
|
||||
|
||||
/** delete chunklist */
|
||||
static void
|
||||
auth_chunk_list_delete(struct auth_chunk* first)
|
||||
{
|
||||
struct auth_chunk* c, *cn;
|
||||
c = first;
|
||||
while(c) {
|
||||
cn = c->next;
|
||||
free(c->data);
|
||||
free(c);
|
||||
c = cn;
|
||||
}
|
||||
}
|
||||
|
||||
/** delete an auth zone structure (tree remove must be done elsewhere) */
|
||||
static void
|
||||
auth_zone_delete(struct auth_zone* z, struct auth_zones* az)
|
||||
@@ -413,6 +427,7 @@ auth_zone_delete(struct auth_zone* z, struct auth_zones* az)
|
||||
}
|
||||
if(z->rpz)
|
||||
rpz_delete(z->rpz);
|
||||
auth_chunk_list_delete(z->perform_write_chunk_list);
|
||||
free(z->name);
|
||||
free(z->zonefile);
|
||||
free(z);
|
||||
@@ -2369,14 +2384,7 @@ static void
|
||||
auth_chunks_delete(struct auth_transfer* at)
|
||||
{
|
||||
if(at->chunks_first) {
|
||||
struct auth_chunk* c, *cn;
|
||||
c = at->chunks_first;
|
||||
while(c) {
|
||||
cn = c->next;
|
||||
free(c->data);
|
||||
free(c);
|
||||
c = cn;
|
||||
}
|
||||
auth_chunk_list_delete(at->chunks_first);
|
||||
}
|
||||
at->chunks_first = NULL;
|
||||
at->chunks_last = NULL;
|
||||
@@ -3593,7 +3601,13 @@ int auth_zones_lookup(struct auth_zones* az, struct query_info* qinfo,
|
||||
*fallback = 1;
|
||||
return 0;
|
||||
}
|
||||
if(z->zone_expired) {
|
||||
if(z->zone_expired || (z->zonemd_check && z->zonemd_callback_env)) {
|
||||
/* Do not serve from a zonemd-check zone while its ZONEMD
|
||||
* verification is still pending: the content is not yet known
|
||||
* to pass the configured check. The pending marker
|
||||
* (zonemd_callback_env) is set under z->lock when the async
|
||||
* lookup is spawned and cleared by the callback under z->lock,
|
||||
* so this test is race-free. */
|
||||
*fallback = z->fallback_enabled;
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
@@ -3695,7 +3709,10 @@ int auth_zones_downstream_answer(struct auth_zones* az, struct module_env* env,
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
}
|
||||
if(z->zone_expired) {
|
||||
if(z->zone_expired || (z->zonemd_check && z->zonemd_callback_env)) {
|
||||
/* see auth_zones_lookup: a pending ZONEMD verification is
|
||||
* treated like expiry - the zone content is not yet known
|
||||
* to pass the configured check. */
|
||||
if(z->fallback_enabled) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
@@ -5299,7 +5316,7 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
|
||||
/** write http chunks to zonefile to create downloaded file */
|
||||
static int
|
||||
auth_zone_write_chunks(struct auth_xfer* xfr, const char* fname)
|
||||
auth_zone_write_chunks(struct auth_chunk* chunk_list, const char* fname)
|
||||
{
|
||||
FILE* out;
|
||||
struct auth_chunk* p;
|
||||
@@ -5308,7 +5325,7 @@ auth_zone_write_chunks(struct auth_xfer* xfr, const char* fname)
|
||||
log_err("could not open %s: %s", fname, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
for(p = xfr->task_transfer->chunks_first; p ; p = p->next) {
|
||||
for(p = chunk_list; p ; p = p->next) {
|
||||
if(!write_out(out, (char*)p->data, p->len)) {
|
||||
log_err("could not write http download to %s", fname);
|
||||
fclose(out);
|
||||
@@ -5319,14 +5336,91 @@ auth_zone_write_chunks(struct auth_xfer* xfr, const char* fname)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** write to zonefile after zone has been updated */
|
||||
/** write to zonefile after zone has been updated, z has rdlock by caller. */
|
||||
static void
|
||||
xfr_write_after_update(struct auth_xfer* xfr, struct module_env* env)
|
||||
zone_write_after_update(struct auth_zone* z, struct module_env* env,
|
||||
struct auth_chunk* chunk_list)
|
||||
{
|
||||
struct config_file* cfg = env->cfg;
|
||||
struct auth_zone* z;
|
||||
char tmpfile[1024];
|
||||
char* zfilename;
|
||||
|
||||
if(z->zonefile == NULL || z->zonefile[0] == 0) {
|
||||
/* no write needed, no zonefile set */
|
||||
auth_chunk_list_delete(chunk_list);
|
||||
return;
|
||||
}
|
||||
zfilename = z->zonefile;
|
||||
if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(zfilename,
|
||||
cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
|
||||
zfilename += strlen(cfg->chrootdir);
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
char nm[LDNS_MAX_DOMAINLEN];
|
||||
dname_str(z->name, nm);
|
||||
verbose(VERB_ALGO, "write zonefile %s for %s", zfilename, nm);
|
||||
}
|
||||
|
||||
/* write to tempfile first */
|
||||
if((size_t)strlen(zfilename) + 16 > sizeof(tmpfile)) {
|
||||
verbose(VERB_ALGO, "tmpfilename too long, cannot update "
|
||||
" zonefile %s", zfilename);
|
||||
auth_chunk_list_delete(chunk_list);
|
||||
return;
|
||||
}
|
||||
snprintf(tmpfile, sizeof(tmpfile), "%s.tmp%u", zfilename,
|
||||
(unsigned)getpid());
|
||||
if(chunk_list) {
|
||||
/* use the stored chunk list to write them */
|
||||
if(!auth_zone_write_chunks(chunk_list, tmpfile)) {
|
||||
unlink(tmpfile);
|
||||
auth_chunk_list_delete(chunk_list);
|
||||
return;
|
||||
}
|
||||
auth_chunk_list_delete(chunk_list);
|
||||
} else if(!auth_zone_write_file(z, tmpfile)) {
|
||||
unlink(tmpfile);
|
||||
return;
|
||||
}
|
||||
#ifdef UB_ON_WINDOWS
|
||||
(void)unlink(zfilename); /* windows does not replace file with rename() */
|
||||
#endif
|
||||
if(rename(tmpfile, zfilename) < 0) {
|
||||
log_err("could not rename(%s, %s): %s", tmpfile, zfilename,
|
||||
strerror(errno));
|
||||
unlink(tmpfile);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** write to zonefile after zone has updated, reacquires z readlock. */
|
||||
static void
|
||||
zone_write_after_update_reacq(uint8_t* bakname, size_t baknamelen,
|
||||
uint16_t bakdclass, struct module_env* env,
|
||||
struct auth_chunk* chunk_list)
|
||||
{
|
||||
struct auth_zone* z;
|
||||
/* get lock again, so it is a readlock and concurrently queries
|
||||
* can be answered */
|
||||
lock_rw_rdlock(&env->auth_zones->lock);
|
||||
z = auth_zone_find(env->auth_zones, bakname, baknamelen, bakdclass);
|
||||
if(!z) {
|
||||
lock_rw_unlock(&env->auth_zones->lock);
|
||||
/* the zone is gone, ignore xfr results */
|
||||
return;
|
||||
}
|
||||
lock_rw_rdlock(&z->lock);
|
||||
lock_rw_unlock(&env->auth_zones->lock);
|
||||
|
||||
zone_write_after_update(z, env, chunk_list);
|
||||
lock_rw_unlock(&z->lock);
|
||||
}
|
||||
|
||||
/** write to zonefile after zone has been updated */
|
||||
static void
|
||||
xfr_write_after_update(struct auth_xfer* xfr, struct module_env* env,
|
||||
struct auth_chunk* chunk_list)
|
||||
{
|
||||
struct auth_zone* z;
|
||||
lock_basic_unlock(&xfr->lock);
|
||||
|
||||
/* get lock again, so it is a readlock and concurrently queries
|
||||
@@ -5344,52 +5438,7 @@ xfr_write_after_update(struct auth_xfer* xfr, struct module_env* env)
|
||||
lock_basic_lock(&xfr->lock);
|
||||
lock_rw_unlock(&env->auth_zones->lock);
|
||||
|
||||
if(z->zonefile == NULL || z->zonefile[0] == 0) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
/* no write needed, no zonefile set */
|
||||
return;
|
||||
}
|
||||
zfilename = z->zonefile;
|
||||
if(cfg->chrootdir && cfg->chrootdir[0] && strncmp(zfilename,
|
||||
cfg->chrootdir, strlen(cfg->chrootdir)) == 0)
|
||||
zfilename += strlen(cfg->chrootdir);
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
char nm[LDNS_MAX_DOMAINLEN];
|
||||
dname_str(z->name, nm);
|
||||
verbose(VERB_ALGO, "write zonefile %s for %s", zfilename, nm);
|
||||
}
|
||||
|
||||
/* write to tempfile first */
|
||||
if((size_t)strlen(zfilename) + 16 > sizeof(tmpfile)) {
|
||||
verbose(VERB_ALGO, "tmpfilename too long, cannot update "
|
||||
" zonefile %s", zfilename);
|
||||
lock_rw_unlock(&z->lock);
|
||||
return;
|
||||
}
|
||||
snprintf(tmpfile, sizeof(tmpfile), "%s.tmp%u", zfilename,
|
||||
(unsigned)getpid());
|
||||
if(xfr->task_transfer->master->http) {
|
||||
/* use the stored chunk list to write them */
|
||||
if(!auth_zone_write_chunks(xfr, tmpfile)) {
|
||||
unlink(tmpfile);
|
||||
lock_rw_unlock(&z->lock);
|
||||
return;
|
||||
}
|
||||
} else if(!auth_zone_write_file(z, tmpfile)) {
|
||||
unlink(tmpfile);
|
||||
lock_rw_unlock(&z->lock);
|
||||
return;
|
||||
}
|
||||
#ifdef UB_ON_WINDOWS
|
||||
(void)unlink(zfilename); /* windows does not replace file with rename() */
|
||||
#endif
|
||||
if(rename(tmpfile, zfilename) < 0) {
|
||||
log_err("could not rename(%s, %s): %s", tmpfile, zfilename,
|
||||
strerror(errno));
|
||||
unlink(tmpfile);
|
||||
lock_rw_unlock(&z->lock);
|
||||
return;
|
||||
}
|
||||
zone_write_after_update(z, env, chunk_list);
|
||||
lock_rw_unlock(&z->lock);
|
||||
}
|
||||
|
||||
@@ -5422,6 +5471,8 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env,
|
||||
int* ixfr_fail)
|
||||
{
|
||||
struct auth_zone* z;
|
||||
int zonemd_in_progress;
|
||||
struct auth_chunk* current_chunk_list = NULL;
|
||||
|
||||
/* obtain locks and structures */
|
||||
lock_basic_unlock(&xfr->lock);
|
||||
@@ -5505,6 +5556,25 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env,
|
||||
if(z->rpz)
|
||||
rpz_finish_config(z->rpz);
|
||||
|
||||
if(z->zonemd_check && z->zonemd_callback_env) {
|
||||
zonemd_in_progress = 1;
|
||||
z->zonemd_callback_perform_write = 1;
|
||||
auth_chunk_list_delete(z->perform_write_chunk_list);
|
||||
z->perform_write_chunk_list = NULL;
|
||||
if(xfr->task_transfer->master->http) {
|
||||
z->perform_write_chunk_list = xfr->task_transfer->chunks_first;
|
||||
xfr->task_transfer->chunks_first = NULL;
|
||||
auth_chunks_delete(xfr->task_transfer);
|
||||
}
|
||||
} else {
|
||||
zonemd_in_progress = 0;
|
||||
z->zonemd_callback_perform_write = 0;
|
||||
if(xfr->task_transfer->master->http) {
|
||||
current_chunk_list = xfr->task_transfer->chunks_first;
|
||||
xfr->task_transfer->chunks_first = NULL;
|
||||
auth_chunks_delete(xfr->task_transfer);
|
||||
}
|
||||
}
|
||||
/* unlock */
|
||||
lock_rw_unlock(&z->lock);
|
||||
|
||||
@@ -5515,7 +5585,9 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env,
|
||||
(unsigned)xfr->serial);
|
||||
}
|
||||
/* see if we need to write to a zonefile */
|
||||
xfr_write_after_update(xfr, env);
|
||||
if(!zonemd_in_progress) {
|
||||
xfr_write_after_update(xfr, env, current_chunk_list);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -8162,7 +8234,8 @@ static int zonemd_dnssec_verify_rrset(struct auth_zone* z,
|
||||
"zonemd: verify %s RRset with DNSKEY", typestr);
|
||||
}
|
||||
sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, sigalg, why_bogus, NULL,
|
||||
LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf, reasonlen);
|
||||
LDNS_SECTION_ANSWER, NULL, NULL, &verified, reasonbuf,
|
||||
reasonlen);
|
||||
if(sec == sec_status_secure) {
|
||||
return 1;
|
||||
}
|
||||
@@ -8511,8 +8584,8 @@ zonemd_get_dnskey_from_anchor(struct auth_zone* z, struct module_env* env,
|
||||
auth_zone_log(z->name, VERB_QUERY,
|
||||
"zonemd: verify DNSKEY RRset with trust anchor");
|
||||
sec = val_verify_DNSKEY_with_TA(env, ve, keystorage, anchor->ds_rrset,
|
||||
anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL, reasonbuf,
|
||||
reasonlen);
|
||||
anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL, NULL,
|
||||
reasonbuf, reasonlen);
|
||||
regional_free_all(env->scratch);
|
||||
if(sec == sec_status_secure) {
|
||||
/* success */
|
||||
@@ -8572,7 +8645,7 @@ auth_zone_verify_zonemd_key_with_ds(struct auth_zone* z,
|
||||
keystorage->rk.rrset_class = htons(z->dclass);
|
||||
auth_zone_log(z->name, VERB_QUERY, "zonemd: verify zone DNSKEY with DS");
|
||||
sec = val_verify_DNSKEY_with_DS(env, ve, keystorage, ds, sigalg,
|
||||
why_bogus, NULL, NULL, reasonbuf, reasonlen);
|
||||
why_bogus, NULL, NULL, NULL, reasonbuf, reasonlen);
|
||||
regional_free_all(env->scratch);
|
||||
if(sec == sec_status_secure) {
|
||||
/* success */
|
||||
@@ -8601,9 +8674,13 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
|
||||
char reasonbuf[256];
|
||||
char* reason = NULL, *ds_bogus = NULL, *typestr="DNSKEY";
|
||||
struct ub_packed_rrset_key* dnskey = NULL, *ds = NULL;
|
||||
int is_insecure = 0, downprot;
|
||||
int is_insecure = 0, downprot, perform_write = 0;
|
||||
struct ub_packed_rrset_key keystorage;
|
||||
uint8_t sigalg[ALGO_NEEDS_MAX+1];
|
||||
uint8_t bakname[LDNS_MAX_DOMAINLEN];
|
||||
size_t baknamelen;
|
||||
uint16_t bakdclass;
|
||||
struct auth_chunk* chunk_list = NULL;
|
||||
|
||||
lock_rw_wrlock(&z->lock);
|
||||
env = z->zonemd_callback_env;
|
||||
@@ -8726,7 +8803,37 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
|
||||
auth_zone_verify_zonemd_with_key(z, env, &env->mesh->mods, dnskey,
|
||||
is_insecure, NULL, downprot?sigalg:NULL);
|
||||
regional_free_all(env->scratch);
|
||||
|
||||
if(z->zonemd_callback_perform_write) {
|
||||
if(!z->zone_expired) {
|
||||
/* Write to zonefile if the ZONEMD is okay. */
|
||||
perform_write = 1;
|
||||
/* copy the key to lookup the z structure.
|
||||
* The new lookup is readonly so concurrent
|
||||
* queries can continue. */
|
||||
if(z->namelen > sizeof(bakname)) {
|
||||
perform_write = 0;
|
||||
auth_chunk_list_delete(z->perform_write_chunk_list);
|
||||
z->perform_write_chunk_list = NULL;
|
||||
} else {
|
||||
memcpy(bakname, z->name, z->namelen);
|
||||
baknamelen = z->namelen;
|
||||
bakdclass = z->dclass;
|
||||
chunk_list = z->perform_write_chunk_list;
|
||||
z->perform_write_chunk_list = NULL;
|
||||
}
|
||||
} else {
|
||||
auth_chunk_list_delete(z->perform_write_chunk_list);
|
||||
z->perform_write_chunk_list = NULL;
|
||||
}
|
||||
z->zonemd_callback_perform_write = 0;
|
||||
}
|
||||
lock_rw_unlock(&z->lock);
|
||||
|
||||
if(perform_write) {
|
||||
zone_write_after_update_reacq(bakname, baknamelen, bakdclass,
|
||||
env, chunk_list);
|
||||
}
|
||||
}
|
||||
|
||||
/** lookup DNSKEY for ZONEMD verification */
|
||||
@@ -8794,6 +8901,9 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env)
|
||||
&auth_zonemd_dnskey_lookup_callback, z, 0,
|
||||
&z->zonemd_callback_unique_info)) {
|
||||
lock_rw_wrlock(&z->lock);
|
||||
/* no callback will run; do not leave the pending
|
||||
* marker set */
|
||||
z->zonemd_callback_env = NULL;
|
||||
log_err("out of memory lookup of %s for zonemd",
|
||||
(fetch_ds?"DS":"DNSKEY"));
|
||||
return 0;
|
||||
|
||||
@@ -146,6 +146,10 @@ struct auth_zone {
|
||||
uint16_t zonemd_callback_qtype;
|
||||
/** for the zonemd callback, the unique info */
|
||||
void* zonemd_callback_unique_info;
|
||||
/** if the zonemd callback should write to file */
|
||||
int zonemd_callback_perform_write;
|
||||
/** chunklist to write for chunked transfer. */
|
||||
struct auth_chunk* perform_write_chunk_list;
|
||||
/** zone has been deleted */
|
||||
int zone_deleted;
|
||||
/** deletelist pointer, unused normally except during delete */
|
||||
|
||||
Vendored
+1
-1
@@ -677,7 +677,7 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
|
||||
rrset_array_unlock(r->ref, r->rrset_count);
|
||||
return NULL;
|
||||
}
|
||||
if(r->security == sec_status_secure && !reply_all_rrsets_secure(r)) {
|
||||
if(r->security == sec_status_secure && !reply_an_ns_rrsets_secure(r)) {
|
||||
/* message rrsets have changed status, revalidate */
|
||||
rrset_array_unlock(r->ref, r->rrset_count);
|
||||
return NULL;
|
||||
|
||||
@@ -2133,7 +2133,7 @@ void listen_start_accept(struct listen_dnsport* listen)
|
||||
}
|
||||
|
||||
struct tcp_req_info*
|
||||
tcp_req_info_create(struct sldns_buffer* spoolbuf)
|
||||
tcp_req_info_create(struct comm_base* base, struct sldns_buffer* spoolbuf)
|
||||
{
|
||||
struct tcp_req_info* req = (struct tcp_req_info*)malloc(sizeof(*req));
|
||||
if(!req) {
|
||||
@@ -2141,6 +2141,12 @@ tcp_req_info_create(struct sldns_buffer* spoolbuf)
|
||||
return NULL;
|
||||
}
|
||||
memset(req, 0, sizeof(*req));
|
||||
req->read_again_timer = comm_timer_create(base, tcp_read_again_cb, req);
|
||||
if(!req->read_again_timer) {
|
||||
log_err("malloc failure");
|
||||
free(req);
|
||||
return NULL;
|
||||
}
|
||||
req->spool_buffer = spoolbuf;
|
||||
return req;
|
||||
}
|
||||
@@ -2150,6 +2156,7 @@ tcp_req_info_delete(struct tcp_req_info* req)
|
||||
{
|
||||
if(!req) return;
|
||||
tcp_req_info_clear(req);
|
||||
comm_timer_delete(req->read_again_timer);
|
||||
/* cp is pointer back to commpoint that owns this struct and
|
||||
* called delete on us */
|
||||
/* spool_buffer is shared udp buffer, not deleted here */
|
||||
@@ -2189,6 +2196,9 @@ void tcp_req_info_clear(struct tcp_req_info* req)
|
||||
req->done_req_list = NULL;
|
||||
req->num_done_req = 0;
|
||||
req->read_is_closed = 0;
|
||||
|
||||
if(comm_timer_is_set(req->read_again_timer))
|
||||
comm_timer_disable(req->read_again_timer);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -4504,7 +4514,7 @@ doq_stream_reset_cb(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id,
|
||||
"unknown stream %d", (int)stream_id);
|
||||
return 0;
|
||||
}
|
||||
if(!doq_stream_close(doq_conn, stream, 0))
|
||||
if(!doq_stream_close(doq_conn, stream, 1))
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -347,6 +347,10 @@ struct tcp_req_info {
|
||||
int num_done_req;
|
||||
/** list of pending writable result packets, malloced one at a time */
|
||||
struct tcp_req_done_item* done_req_list;
|
||||
/** the read again timer, when the number of pipelined TCP queries
|
||||
* is large, it waits, zero time, for a new event loop to service
|
||||
* the remainder of the TCP traffic on the fd. */
|
||||
struct comm_timer* read_again_timer;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -377,10 +381,12 @@ struct tcp_req_done_item {
|
||||
* Create tcp request info structure that keeps track of open
|
||||
* requests on the TCP channel that are resolved at the same time,
|
||||
* and the pending results that have to get written back to that client.
|
||||
* @param base: comm base for read again timer.
|
||||
* @param spoolbuf: shared buffer
|
||||
* @return new structure or NULL on alloc failure.
|
||||
*/
|
||||
struct tcp_req_info* tcp_req_info_create(struct sldns_buffer* spoolbuf);
|
||||
struct tcp_req_info* tcp_req_info_create(struct comm_base* base,
|
||||
struct sldns_buffer* spoolbuf);
|
||||
|
||||
/**
|
||||
* Delete tcp request structure. Called by owning commpoint.
|
||||
|
||||
+73
-75
@@ -373,7 +373,7 @@ mesh_serve_expired_lookup(struct module_qstate* qstate,
|
||||
"validation");
|
||||
goto bail_out; /* need to validate cache entry first */
|
||||
} else if(msg->rep->security == sec_status_secure &&
|
||||
!reply_all_rrsets_secure(msg->rep) && must_validate) {
|
||||
!reply_an_ns_rrsets_secure(msg->rep) && must_validate) {
|
||||
verbose(VERB_ALGO, "Serve expired: secure entry"
|
||||
" changed status");
|
||||
goto bail_out; /* rrset changed, re-verify */
|
||||
@@ -1097,6 +1097,18 @@ mesh_state_make_unique(struct mesh_state* mstate)
|
||||
mstate->unique = mstate;
|
||||
}
|
||||
|
||||
/** pop a reply from the reply list, if there are any. */
|
||||
static struct mesh_reply*
|
||||
mesh_reply_list_pop_first(struct mesh_state* mstate)
|
||||
{
|
||||
if(mstate->reply_list) {
|
||||
struct mesh_reply* r = mstate->reply_list;
|
||||
mstate->reply_list = r->next;
|
||||
return r;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mesh_state_cleanup(struct mesh_state* mstate)
|
||||
{
|
||||
@@ -1112,15 +1124,30 @@ mesh_state_cleanup(struct mesh_state* mstate)
|
||||
}
|
||||
/* drop unsent replies */
|
||||
if(!mstate->replies_sent) {
|
||||
struct mesh_reply* rep = mstate->reply_list;
|
||||
struct mesh_reply* rep;
|
||||
struct mesh_cb* cb;
|
||||
/* in tcp_req_info, the mstates linked are removed, but
|
||||
* the reply_list is now NULL, so the remove-from-empty-list
|
||||
* takes no time and also it does not do the mesh accounting */
|
||||
mstate->reply_list = NULL;
|
||||
for(; rep; rep=rep->next) {
|
||||
/* Pop items from the list, that means there is no iterator.
|
||||
* And then items can be removed from the reply list, from
|
||||
* like comm_point_drop_reply and comm_point_close calls.
|
||||
* As the tcp_req_info and http2 code drops the entire
|
||||
* connection. That could delete mesh_reply items previous and
|
||||
* after the current state. The previous items are already
|
||||
* popped. And the next items can be altered, like to when a
|
||||
* connection has more replies on the reply list.
|
||||
* The current item is also popped so the code needs to
|
||||
* remove its references. */
|
||||
while((rep = mesh_reply_list_pop_first(mstate)) != NULL) {
|
||||
infra_wait_limit_dec(mesh->env->infra_cache,
|
||||
&rep->query_reply, mesh->env->cfg);
|
||||
if(rep->query_reply.c->tcp_req_info)
|
||||
tcp_req_info_remove_mesh_state(
|
||||
rep->query_reply.c->tcp_req_info,
|
||||
mstate);
|
||||
else if(rep->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(rep->h2_stream);
|
||||
else if(rep->query_reply.doq_stream)
|
||||
doq_stream_remove_mesh_state(
|
||||
rep->query_reply.doq_stream);
|
||||
comm_point_drop_reply(&rep->query_reply);
|
||||
log_assert(mesh->num_reply_addrs > 0);
|
||||
mesh->num_reply_addrs--;
|
||||
@@ -1484,12 +1511,6 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
struct timeval end_time;
|
||||
struct timeval duration;
|
||||
int secure;
|
||||
/* briefly set the replylist to null in case the
|
||||
* meshsendreply calls tcpreqinfo sendreply that
|
||||
* comm_point_drops because of size, and then the
|
||||
* null stops the mesh state remove and thus
|
||||
* reply_list modification and accounting */
|
||||
struct mesh_reply* rlist = m->reply_list;
|
||||
|
||||
/* rpz: apply actions */
|
||||
rcode = mesh_is_udp(r) && mesh_is_rpz_respip_tcponly_action(m)
|
||||
@@ -1546,9 +1567,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
sldns_buffer_write_at(r_buffer, 0, &r->qid, sizeof(uint16_t));
|
||||
sldns_buffer_write_at(r_buffer, 12, r->qname,
|
||||
m->s.qinfo.qname_len);
|
||||
m->reply_list = NULL;
|
||||
comm_point_send_reply(&r->query_reply);
|
||||
m->reply_list = rlist;
|
||||
} else if(rcode) {
|
||||
m->s.qinfo.qname = r->qname;
|
||||
m->s.qinfo.local_alias = r->local_alias;
|
||||
@@ -1570,9 +1589,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
}
|
||||
error_encode(r_buffer, rcode, &m->s.qinfo, r->qid,
|
||||
r->qflags, &r->edns);
|
||||
m->reply_list = NULL;
|
||||
comm_point_send_reply(&r->query_reply);
|
||||
m->reply_list = rlist;
|
||||
} else {
|
||||
size_t udp_size = r->edns.udp_size;
|
||||
r->edns.edns_version = EDNS_ADVERTISED_VERSION;
|
||||
@@ -1608,9 +1625,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
|
||||
&m->s.qinfo, r->qid, r->qflags, &r->edns);
|
||||
}
|
||||
m->reply_list = NULL;
|
||||
comm_point_send_reply(&r->query_reply);
|
||||
m->reply_list = rlist;
|
||||
}
|
||||
infra_wait_limit_dec(m->s.env->infra_cache, &r->query_reply,
|
||||
m->s.env->cfg);
|
||||
@@ -1762,6 +1777,7 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
struct reply_info* rep = (mstate->s.return_msg?
|
||||
mstate->s.return_msg->rep:NULL);
|
||||
struct timeval tv = {0, 0};
|
||||
struct mesh_area* mesh = mstate->s.env->mesh;
|
||||
int i = 0;
|
||||
/* No need for the serve expired timer anymore; we are going to reply. */
|
||||
if(mstate->s.serve_expired_data) {
|
||||
@@ -1786,7 +1802,18 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
&& (!rep || rep->security != sec_status_secure))
|
||||
dns_error_reporting(&mstate->s, rep);
|
||||
|
||||
for(r = mstate->reply_list; r; r = r->next) {
|
||||
while((r = mesh_reply_list_pop_first(mstate)) != NULL) {
|
||||
|
||||
/* it was not detached (because it had a reply list), could be now */
|
||||
if(!mstate->reply_list && !mstate->cb_list
|
||||
&& mstate->super_set.count == 0) {
|
||||
mesh->num_detached_states++;
|
||||
}
|
||||
/* if not replies any more in mstate, it is no longer a reply_state */
|
||||
if(!mstate->reply_list && !mstate->cb_list) {
|
||||
log_assert(mesh->num_reply_states > 0);
|
||||
mesh->num_reply_states--;
|
||||
}
|
||||
if(mesh_is_udp(r)) {
|
||||
/* For UDP queries, the old replies are discarded.
|
||||
* This stops a large volume of old replies from
|
||||
@@ -1801,22 +1828,18 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
|
||||
mstate->s.env->cfg->discard_timeout) {
|
||||
/* Drop the reply, it is too old */
|
||||
/* briefly set the reply_list to NULL, so that the
|
||||
* tcp req info cleanup routine that calls the mesh
|
||||
* to deregister the meshstate for it is not done
|
||||
* because the list is NULL and also accounting is not
|
||||
* done there, but instead we do that here. */
|
||||
struct mesh_reply* reply_list = mstate->reply_list;
|
||||
verbose(VERB_ALGO, "drop reply, it is older than discard-timeout");
|
||||
infra_wait_limit_dec(mstate->s.env->infra_cache,
|
||||
&r->query_reply, mstate->s.env->cfg);
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2)
|
||||
if(r->query_reply.c->tcp_req_info)
|
||||
tcp_req_info_remove_mesh_state(
|
||||
r->query_reply.c->tcp_req_info,
|
||||
mstate);
|
||||
else if(r->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(r->h2_stream);
|
||||
else if(r->query_reply.doq_stream)
|
||||
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
mstate->reply_list = reply_list;
|
||||
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
|
||||
mstate->s.env->mesh->num_reply_addrs--;
|
||||
mstate->s.env->mesh->num_queries_discard_timeout++;
|
||||
@@ -1841,22 +1864,17 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
/* if this query is determined to be dropped during the
|
||||
* mesh processing, this is the point to take that action. */
|
||||
if(mstate->s.is_drop) {
|
||||
/* briefly set the reply_list to NULL, so that the
|
||||
* tcp req info cleanup routine that calls the mesh
|
||||
* to deregister the meshstate for it is not done
|
||||
* because the list is NULL and also accounting is not
|
||||
* done there, but instead we do that here. */
|
||||
struct mesh_reply* reply_list = mstate->reply_list;
|
||||
infra_wait_limit_dec(mstate->s.env->infra_cache,
|
||||
&r->query_reply, mstate->s.env->cfg);
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2) {
|
||||
if(r->query_reply.c->tcp_req_info) {
|
||||
tcp_req_info_remove_mesh_state(
|
||||
r->query_reply.c->tcp_req_info, mstate);
|
||||
} else if(r->query_reply.c->use_h2) {
|
||||
http2_stream_remove_mesh_state(r->h2_stream);
|
||||
} else if(r->query_reply.doq_stream) {
|
||||
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
|
||||
}
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
mstate->reply_list = reply_list;
|
||||
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
|
||||
mstate->s.env->mesh->num_reply_addrs--;
|
||||
} else {
|
||||
@@ -1897,18 +1915,6 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
}
|
||||
}
|
||||
|
||||
/* Mesh area accounting */
|
||||
if(mstate->reply_list) {
|
||||
mstate->reply_list = NULL;
|
||||
if(!mstate->reply_list && !mstate->cb_list) {
|
||||
/* was a reply state, not anymore */
|
||||
log_assert(mstate->s.env->mesh->num_reply_states > 0);
|
||||
mstate->s.env->mesh->num_reply_states--;
|
||||
}
|
||||
if(!mstate->reply_list && !mstate->cb_list &&
|
||||
mstate->super_set.count == 0)
|
||||
mstate->s.env->mesh->num_detached_states++;
|
||||
}
|
||||
mstate->replies_sent = 1;
|
||||
|
||||
while((c = mstate->cb_list) != NULL) {
|
||||
@@ -2498,7 +2504,6 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
apply_respip_action(struct module_qstate* qstate,
|
||||
const struct query_info* qinfo, struct respip_client_info* cinfo,
|
||||
@@ -2631,7 +2636,18 @@ mesh_serve_expired_callback(void* arg)
|
||||
if(verbosity >= VERB_ALGO)
|
||||
log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep);
|
||||
|
||||
for(r = mstate->reply_list; r; r = r->next) {
|
||||
while((r = mesh_reply_list_pop_first(mstate)) != NULL) {
|
||||
|
||||
/* it was not detached (because it had a reply list), could be now */
|
||||
if(!mstate->reply_list && !mstate->cb_list
|
||||
&& mstate->super_set.count == 0) {
|
||||
mesh->num_detached_states++;
|
||||
}
|
||||
/* if not replies any more in mstate, it is no longer a reply_state */
|
||||
if(!mstate->reply_list && !mstate->cb_list) {
|
||||
log_assert(mesh->num_reply_states > 0);
|
||||
mesh->num_reply_states--;
|
||||
}
|
||||
if(mesh_is_udp(r)) {
|
||||
struct timeval old;
|
||||
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
|
||||
@@ -2639,22 +2655,17 @@ mesh_serve_expired_callback(void* arg)
|
||||
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
|
||||
mstate->s.env->cfg->discard_timeout) {
|
||||
/* Drop the reply, it is too old */
|
||||
/* briefly set the reply_list to NULL, so that the
|
||||
* tcp req info cleanup routine that calls the mesh
|
||||
* to deregister the meshstate for it is not done
|
||||
* because the list is NULL and also accounting is not
|
||||
* done there, but instead we do that here. */
|
||||
struct mesh_reply* reply_list = mstate->reply_list;
|
||||
verbose(VERB_ALGO, "drop reply, it is older than discard-timeout");
|
||||
infra_wait_limit_dec(mstate->s.env->infra_cache,
|
||||
&r->query_reply, mstate->s.env->cfg);
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2)
|
||||
if(r->query_reply.c->tcp_req_info)
|
||||
tcp_req_info_remove_mesh_state(
|
||||
r->query_reply.c->tcp_req_info, mstate);
|
||||
else if(r->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(r->h2_stream);
|
||||
else if(r->query_reply.doq_stream)
|
||||
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
mstate->reply_list = reply_list;
|
||||
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
|
||||
mstate->s.env->mesh->num_reply_addrs--;
|
||||
mstate->s.env->mesh->num_queries_discard_timeout++;
|
||||
@@ -2692,8 +2703,7 @@ mesh_serve_expired_callback(void* arg)
|
||||
if(r->query_reply.c->tcp_req_info)
|
||||
tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate);
|
||||
/* mesh_send_reply removed mesh state from http2_stream. */
|
||||
infra_wait_limit_dec(mstate->s.env->infra_cache,
|
||||
&r->query_reply, mstate->s.env->cfg);
|
||||
/* mesh_send_reply decremented wait_limit. */
|
||||
prev = r;
|
||||
prev_buffer = r_buffer;
|
||||
}
|
||||
@@ -2712,18 +2722,6 @@ mesh_serve_expired_callback(void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
/* Mesh area accounting */
|
||||
if(mstate->reply_list) {
|
||||
mstate->reply_list = NULL;
|
||||
if(!mstate->reply_list && !mstate->cb_list) {
|
||||
log_assert(mesh->num_reply_states > 0);
|
||||
mesh->num_reply_states--;
|
||||
if(mstate->super_set.count == 0) {
|
||||
mesh->num_detached_states++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while((c = mstate->cb_list) != NULL) {
|
||||
/* take this cb off the list; so that the list can be
|
||||
* changed, eg. by adds from the callback routine */
|
||||
|
||||
@@ -786,3 +786,13 @@ size_t doq_table_quic_size_get(struct doq_table* ATTR_UNUSED(table))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void tcp_read_again_cb(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
void tcp_more_read_again_cb(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
+143
-1
@@ -196,7 +196,7 @@ verifytest_rrset(struct module_env* env, struct val_env* ve,
|
||||
setup_sigalg(dnskey, sigalg); /* check all algorithms in the dnskey */
|
||||
/* ok to give null as qstate here, won't be used for answer section. */
|
||||
sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason,
|
||||
NULL, LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf,
|
||||
NULL, LDNS_SECTION_ANSWER, NULL, NULL, &verified, reasonbuf,
|
||||
sizeof(reasonbuf));
|
||||
if(vsig) {
|
||||
printf("verify outcome is: %s %s\n", sec_status_to_string(sec),
|
||||
@@ -510,6 +510,146 @@ nsec3_hash_test(const char* fname)
|
||||
sldns_buffer_free(buf);
|
||||
}
|
||||
|
||||
/** Test the rrset_canonicalize_to_buffer function to see if the
|
||||
* size of canon_owner name is properly checked for. */
|
||||
static void
|
||||
canon_owner_buf_test(void)
|
||||
{
|
||||
struct regional* region;
|
||||
sldns_buffer* buf;
|
||||
struct ub_packed_rrset_key k;
|
||||
struct packed_rrset_data d;
|
||||
size_t rr_len[2];
|
||||
time_t rr_ttl[2];
|
||||
uint8_t* rr_data[2];
|
||||
int ret;
|
||||
unit_show_func("validator/val_sigcrypt.c",
|
||||
"rrset_canonicalize_to_buffer");
|
||||
region = regional_create();
|
||||
if(!region)
|
||||
fatal_exit("out of memory");
|
||||
/* Purposefully a very small buffer, to overflow it */
|
||||
buf = sldns_buffer_new(28);
|
||||
if(!buf)
|
||||
fatal_exit("out of memory");
|
||||
|
||||
/* An RRset to canonicalize. The buffer is made smaller, so
|
||||
* it can fail on bounds checks. */
|
||||
memset(&d, 0, sizeof(d));
|
||||
d.ttl = 3600;
|
||||
d.count = 1;
|
||||
d.rrsig_count = 1;
|
||||
d.rr_len = rr_len;
|
||||
d.rr_ttl = rr_ttl;
|
||||
d.rr_data = rr_data;
|
||||
rr_len[0] = 18;
|
||||
rr_len[1] = 36;
|
||||
rr_ttl[0] = 3600;
|
||||
rr_ttl[1] = 3600;
|
||||
rr_data[0] = (uint8_t*)"\x00\x10\x0Fzzaaaaaaaaaaaaa";
|
||||
rr_data[1] = (uint8_t*)"\x00\x24\x00\x06\x08\x3\x01\x02\x03\x04\x01\x02\x03\x04\x01\x02\x03\x04\x12\x34\x03zzz\x00zzaaaaaaaaaaa";
|
||||
|
||||
memset(&k, 0, sizeof(k));
|
||||
k.rk.dname = (uint8_t*) "\x0f" "aaaaaaaaaaaaaaa" "\x00";
|
||||
k.rk.dname_len = 17;
|
||||
k.rk.type = htons(LDNS_RR_TYPE_TXT);
|
||||
k.rk.rrset_class = htons(LDNS_RR_CLASS_IN);
|
||||
k.entry.data = &d;
|
||||
|
||||
/* There should be no buffer overflow, assertion failure, here */
|
||||
ret = rrset_canonicalize_to_buffer(region, buf, &k);
|
||||
unit_assert(ret == 0);
|
||||
|
||||
regional_destroy(region);
|
||||
sldns_buffer_free(buf);
|
||||
}
|
||||
|
||||
/** Test if ds_digest_match_dnskey that calls ds_create_dnskey_digest,
|
||||
* checks the buffer size. */
|
||||
static void
|
||||
dnskey_ds_digest_test(void)
|
||||
{
|
||||
struct regional* region;
|
||||
sldns_buffer* buf;
|
||||
struct module_env env;
|
||||
struct ub_packed_rrset_key k1, k2;
|
||||
struct packed_rrset_data d1, d2;
|
||||
size_t rr_len1[1], rr_len2[1];
|
||||
time_t rr_ttl1[1], rr_ttl2[1];
|
||||
uint8_t* rr_rdata1[1], *rr_rdata2[1];
|
||||
int ret;
|
||||
unit_show_func("validator/val_sigcrypt.c", "ds_digest_match_dnskey");
|
||||
region = regional_create();
|
||||
if(!region)
|
||||
fatal_exit("out of memory");
|
||||
/* Purposefully a very small buffer, to overflow it */
|
||||
buf = sldns_buffer_new(28);
|
||||
if(!buf)
|
||||
fatal_exit("out of memory");
|
||||
memset(&env, 0, sizeof(env));
|
||||
env.scratch = region;
|
||||
env.scratch_buffer = buf;
|
||||
|
||||
/* A DNSKEY and DS RRset to match together. The buffer is made
|
||||
* smaller, so it can fail on bounds checks. */
|
||||
memset(&d1, 0, sizeof(d1));
|
||||
d1.ttl = 3600;
|
||||
d1.count = 1;
|
||||
d1.rr_len = rr_len1;
|
||||
d1.rr_ttl = rr_ttl1;
|
||||
d1.rr_data = rr_rdata1;
|
||||
rr_len1[0] = 38;
|
||||
rr_ttl1[0] = 3600;
|
||||
/* DS rdata has: keytag (2bytes), algorithm (1byte),
|
||||
* digesttype (1byte), digest (remainder). */
|
||||
rr_rdata1[0] = (uint8_t*)"\x00\x24"
|
||||
"\x12\x34"
|
||||
"\x08" /* RSASHA256 */
|
||||
"\x02" /* SHA256 */
|
||||
"0123456789abcdef0123456789abcdef"; /* 32 bytes */
|
||||
;
|
||||
|
||||
memset(&k1, 0, sizeof(k1));
|
||||
k1.rk.dname = (uint8_t*) "\x03" "foo" "\x00";
|
||||
k1.rk.dname_len = 5;
|
||||
k1.rk.type = htons(LDNS_RR_TYPE_DS);
|
||||
k1.rk.rrset_class = htons(LDNS_RR_CLASS_IN);
|
||||
k1.entry.data = &d1;
|
||||
|
||||
memset(&d2, 0, sizeof(d2));
|
||||
d2.ttl = 3600;
|
||||
d2.count = 1;
|
||||
d2.rr_len = rr_len2;
|
||||
d2.rr_ttl = rr_ttl2;
|
||||
d2.rr_data = rr_rdata2;
|
||||
rr_len2[0] = 38;
|
||||
rr_ttl2[0] = 3600;
|
||||
/* DNSKEY rdata has: flags (2bytes), protocol (1byte),
|
||||
* algorithm (1byte), publickey (remainder). */
|
||||
rr_rdata2[0] = (uint8_t*)"\x00\x24"
|
||||
"\x01\x01" /* KSK */
|
||||
"\x03" /* DNSSEC_KEYPROTO */
|
||||
"\x08" /* RSASHA256 */
|
||||
"0123456789abcdef0123456789abcdef"; /* 32 bytes of content */
|
||||
;
|
||||
|
||||
memset(&k2, 0, sizeof(k2));
|
||||
k2.rk.dname = (uint8_t*) "\x03" "foo" "\x00";
|
||||
k2.rk.dname_len = 5;
|
||||
k2.rk.type = htons(LDNS_RR_TYPE_DNSKEY);
|
||||
k2.rk.rrset_class = htons(LDNS_RR_CLASS_IN);
|
||||
k2.entry.data = &d2;
|
||||
/* 36 byte rdata length for DNSKEY (38-2), and dname length of 5,
|
||||
* exceeds the (small) buffer size. */
|
||||
|
||||
/* There should be no buffer overflow, assertion failure, here */
|
||||
ret = ds_digest_match_dnskey(&env, &k2, 0, &k1, 0);
|
||||
unit_assert(ret == 0);
|
||||
|
||||
regional_destroy(region);
|
||||
sldns_buffer_free(buf);
|
||||
}
|
||||
|
||||
#define xstr(s) str(s)
|
||||
#define str(s) #s
|
||||
|
||||
@@ -724,4 +864,6 @@ verify_test(void)
|
||||
#endif
|
||||
nsectest();
|
||||
nsec3_hash_test(SRCDIRSTR "/testdata/test_nsec3_hash.1");
|
||||
dnskey_ds_digest_test();
|
||||
canon_owner_buf_test();
|
||||
}
|
||||
|
||||
@@ -85,6 +85,15 @@ for input in $PRE/testdata/*.rpl $PRE/testdata/*.crpl; do
|
||||
fi
|
||||
fi
|
||||
|
||||
# detect if ECDSA is needed
|
||||
if echo $cleaninput | grep ecdsa >/dev/null 2>&1; then
|
||||
if $PRE/testbound -e >/dev/null 2>&1; then
|
||||
: # ECDSA is supported
|
||||
else
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# detect if CLIENT_SUBNET is needed
|
||||
if echo $cleaninput | grep subnet >/dev/null 2>&1; then
|
||||
if $PRE/testbound -c >/dev/null 2>&1; then
|
||||
|
||||
+1
-31
@@ -283,39 +283,9 @@ www.example.com. IN A
|
||||
SECTION ANSWER
|
||||
ENTRY_END
|
||||
|
||||
; the zonefile was updated with new contents
|
||||
; the zonefile was not updated with new contents, due to zonemd failure
|
||||
STEP 70 CHECK_TEMPFILE example.com
|
||||
FILE_BEGIN
|
||||
example.com. 3600 IN SOA ns.example.com. hostmaster.example.com. 200154054 28800 7200 604800 3600
|
||||
example.com. 3600 IN RRSIG SOA 8 2 3600 20201116135527 20201019135527 55566 example.com. gcFHT/Q4iDZ78CK6fyY2HZr8sRtgH2Rna9fEs06RW0gqMnfDntweoIaBamOZ7NlAP84aY2bZeanmEccmkHexByUpodCoKQ4NzVXctLr0TO4PVoFyfUfj62fjhM56SF8ioDxsoDQcPtYXcjNQjwfntWofMqHCMxrb9LzbgePzhOM=
|
||||
example.com. 3600 IN NS ns.example.com.
|
||||
example.com. 3600 IN RRSIG NS 8 2 3600 20201116135527 20201019135527 55566 example.com. X+V3XsbJbBi9OsHpjMkGCox8RLY/uXp/XX/O/flTrIre9fMDWm9ZGnewtuQFpLgGc6hUTi0eLsuRWRA5fZXEKUBhmoR2Ph01KgE1gvlL7v6zPWQwXVcBRUr3mOSbYdNNkHkXEjiDBGEhNkfqR216zNgw563eEGXOkLUFNIx5Zpg=
|
||||
example.com. 3600 IN NSEC bar.example.com. NS SOA RRSIG NSEC DNSKEY ZONEMD
|
||||
example.com. 3600 IN RRSIG NSEC 8 2 3600 20201116135527 20201019135527 55566 example.com. ufLrlOQprAqjnH85Rt3T0Mxd3ZB0mBeeNIr84eFJ8Rk6WiWEPm0Y1R7GRufNI24Mj7iqLcL4nJM6KK6B7dJqjqu73jw1acuYNnbsoV2BNDRXRFP2FNWTpctVdi+955f3FzgsmEJXfGiSUG0YXAEcZmdCPCn5ii2jk8mk7r6KKYo=
|
||||
example.com. 3600 IN DNSKEY 256 3 8 AwEAAdug/L739i0mgN2nuK/bhxu3wFn5Ud9nK2+XUmZQlPUEZUC5YZvm1rfMmEWTGBn87fFxEu/kjFZHJ55JLzqsbbpVHLbmKCTT2gYR2FV2WDKROGKuYbVkJIXdKAjJ0ONuK507NinYvlWXIoxHn22KAWOd9wKgSTNHBlmGkX+ts3hh ;{id = 55566}
|
||||
example.com. 3600 IN RRSIG DNSKEY 8 2 3600 20201116135527 20201019135527 55566 example.com. fsdnVg38PKQTH2mDOwkXL6Jre7JP7Gf8WI3CvIbmeYQUJtAlpcSbZkS3wInm3kKMxOuT55BWzndQzpfmpo91OqJjG27W0k9301NMLUwFprA6b9HK+iPAT0JpYPDPzcm1bQdarLzLS+eD/GPwmyVSX7Gze+08VfE8m8sOW2r7UjA=
|
||||
example.com. 3600 IN ZONEMD 200154054 1 2 58F7620F93204BBB31B44F795B3409CC4ABD9EF5601DECC15675BD7751213152984EDDCE0626E6062E744B03B3E47711202FBB79E4A2EB8BC5CF46741B5CAE6F
|
||||
example.com. 3600 IN RRSIG ZONEMD 8 2 3600 20201116135527 20201019135527 55566 example.com. orn8ZF/yqj9u4WrhiO6gtEcTaVsnZSWWZLfXhcIOiWSB8kKCxtZl5cG17dD3Du1NllUwMRqkp0KleLhIoUS9xeQ/0x05u+CYLrfQ62oAiD7q54ZQzpXJIH52aQzKV70ZnO03CZowhQBnetmIoKX6xLogKo8pt+BdQbo3oVHxV8Y=
|
||||
bar.example.com. 3600 IN A 1.2.3.55
|
||||
bar.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. NYhmRicF4C9+YxpWeQrepy4ALM1CM0USoDuGi3W5Xtp4/+YpCJfSIdR9vlJaJ2WayYuZrz9Ai2ci7oWwE1Fn3oywGwCKvGo9m0c3mC2eEtphE19wrop6pWu6um4RiFhmzYS1voraA3PAdYzze9U4NHzlk0+sb5vNZW9dSZS30Ds=
|
||||
bar.example.com. 3600 IN NSEC ding.example.com. A RRSIG NSEC
|
||||
bar.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. VhsGuBx20DXQZNU8ITAMnasn6NVyEjN9xtB8msH5xJn80UCuaqvFBURzcPWN3aHnykEvGfdPF/9P3WvlON0cMikWkqSLy6Q9bpvgAq13HWYh+ZcDoqLtICaB7RkBQc+6aHAqZFyQbD8/m8Kxt5eVJtV6rEuf+yPX0+3aXHhsRg0=
|
||||
ding.example.com. 3600 IN A 1.2.3.4
|
||||
ding.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. OERsruISkpd1s68ute8Xm8YXisBCTkkiDMt34K+0dVqvySOJq63d3qN18BeUxZxLyHDB1eR3nZZKqEdkTqrv2r98skhWhjnOECpFbu5gKjtN/KPexbbJ+rxC0QqciuWOC7M6YE0cvI17/RB9KhVRy5rqY2X4Gt2wk2CNeD1dAko=
|
||||
ding.example.com. 3600 IN NSEC foo.example.com. A RRSIG NSEC
|
||||
ding.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. nb1W2aaKrU5iAQiY8gMsoMOejID19JMTEwY2rRoe+KsvzMs0rE0ifEkqit4blXaU0tfy0foJ70uqdJFqBoGz1NcSwZ6GNk/iNfGvG3XpxZ/zqEe7kkIucqqei794G7z9psqV94yZ3WaT+IswPpWrSaWv1w41RtcWufPhe4fOAmU=
|
||||
foo.example.com. 3600 IN A 1.2.3.4
|
||||
foo.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. ZcUngb2pUejwnsshbJN/Dfr+Bzu8fcZXyqLArQ+10Bw1IPHyfx7yyUJ43V5tTYVHPSEsJzTnaWj+olVrNhVZxq5e0pgzSYPfGln2FEItEvMIOn33j8yKTpPW2MLyuFF5ZkXhosG20EUwRMvMmRHRz9mIZfwWoMbSGPukmLh8zMA=
|
||||
foo.example.com. 3600 IN NSEC ns.example.com. A RRSIG NSEC
|
||||
foo.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. fUZEpkEULRWDntN5Z7Kr8M83Hjhf08ECMKRpo6IBoBc3ayenj+YMgWAvFXC825wjENPYYWNGag0d32U83zCZxqgv+8uXZd3B7QDpTbL41aWZdc++s5YWTkYjyOWwJ1XHOv4nL3qEnJBXVzo/E1gbSKhTFuG97i+7J1MFd9MsC5s=
|
||||
ns.example.com. 3600 IN A 127.0.0.1
|
||||
ns.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. SiuxuPtN/ITd+Z20j8UNUHJWbLHirE8zQOWMv5fAZ1rPKpAidrZgUL8J417GdrTwkueU2ywAJ7EzFJSwNTa7o/wUnq7svmOR6Ze6UQsKuZFZGEfqPNDRp4YuF86LU5jChuo+f/IRpydHrxVwGxDPCR9KarDM+ewfW+yI5bZeZcg=
|
||||
ns.example.com. 3600 IN NSEC www.example.com. A RRSIG NSEC
|
||||
ns.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. 0upKNYjiow4NDJm3I1RbUddE9GGuFYEVKswww5BAc/6WHuukupncL30lskvcSKGpByDssP2Hi2CufyEtYeGWh6q1TxtOFRqFBX1p6Q5b3tBlCtvv4h31dQR9uqLvq+GkGS5MR+0LO5kWagIpZmnI8YY5plVdXEtNbp2Ar8zvz/A=
|
||||
www.example.com. 3600 IN A 127.0.0.1
|
||||
www.example.com. 3600 IN RRSIG A 8 3 3600 20201116135527 20201019135527 55566 example.com. AaIeICaPjV50TDrpbyOn94+hs8EYIMTmN4pYqj7e8GIGimqQIk5jgpwSx6SOoOF+uOqkf9GKHkQTn5YVGaeXwEQleg7mPTmMYKAOk06Y7MFUO1Vwt1Vt7Wo+Cpa3x2a1CmEkfFOi4WqP43VJnUtjjKmXoKRz3VUmqByyJYUAGbQ=
|
||||
www.example.com. 3600 IN NSEC example.com. A RRSIG NSEC
|
||||
www.example.com. 3600 IN RRSIG NSEC 8 3 3600 20201116135527 20201019135527 55566 example.com. meg/t6nIBqQZ0d5/dT7uu/3CuP4vE+HxqFQaj2fjUNceA/6C7QIQnqQ5Kyblg+XijDkQX0yvyFNHYdgF16UDgFT7tlNUCHk1SpF5BWzV4c4tBEhxASTz7UQo111O3Tyd6CldPzO/Se15Ud0/ZYltHEqWTfY5nJoXC/OJD9V2QOI=
|
||||
FILE_END
|
||||
|
||||
SCENARIO_END
|
||||
|
||||
Vendored
+1
@@ -11,6 +11,7 @@ server:
|
||||
trust-anchor-signaling: no
|
||||
iter-scrub-promiscuous: no
|
||||
rrset-roundrobin: no
|
||||
val-clean-additional: yes
|
||||
|
||||
stub-zone:
|
||||
name: "."
|
||||
|
||||
Vendored
+1
@@ -12,6 +12,7 @@ server:
|
||||
minimal-responses: no
|
||||
iter-scrub-promiscuous: no
|
||||
rrset-roundrobin: no
|
||||
val-clean-additional: yes
|
||||
|
||||
stub-zone:
|
||||
name: "."
|
||||
|
||||
+7
-1
@@ -278,7 +278,7 @@ config_create(void)
|
||||
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_clean_additional = 0; /* off to protect against much data. */
|
||||
cfg->val_log_level = 0;
|
||||
cfg->val_log_squelch = 0;
|
||||
cfg->val_permissive_mode = 0;
|
||||
@@ -429,6 +429,8 @@ config_create(void)
|
||||
cfg->iter_scrub_rrsig = 8;
|
||||
cfg->iter_scrub_promiscuous = 1;
|
||||
cfg->max_global_quota = 200;
|
||||
cfg->val_validation_attempts = 32;
|
||||
cfg->val_hash_attempts = 32;
|
||||
return cfg;
|
||||
error_exit:
|
||||
config_delete(cfg);
|
||||
@@ -785,6 +787,8 @@ int config_set_option(struct config_file* cfg, const char* opt,
|
||||
else S_NUMBER_OR_ZERO("iter-scrub-rrsig:", iter_scrub_rrsig)
|
||||
else S_YNO("iter-scrub-promiscuous:", iter_scrub_promiscuous)
|
||||
else S_NUMBER_OR_ZERO("max-global-quota:", max_global_quota)
|
||||
else S_NUMBER_OR_ZERO("val-validation-attempts:", val_validation_attempts)
|
||||
else S_NUMBER_OR_ZERO("val-hash-attempts:", val_hash_attempts)
|
||||
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)
|
||||
@@ -1265,6 +1269,8 @@ config_get_option(struct config_file* cfg, const char* opt,
|
||||
else O_DEC(opt, "iter-scrub-rrsig", iter_scrub_rrsig)
|
||||
else O_YNO(opt, "iter-scrub-promiscuous", iter_scrub_promiscuous)
|
||||
else O_DEC(opt, "max-global-quota", max_global_quota)
|
||||
else O_DEC(opt, "val-validation-attempts", val_validation_attempts)
|
||||
else O_DEC(opt, "val-hash-attempts", val_hash_attempts)
|
||||
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)
|
||||
|
||||
@@ -798,6 +798,10 @@ struct config_file {
|
||||
int iter_scrub_rrsig;
|
||||
/** limit on upstream queries for an incoming query and subqueries. */
|
||||
int max_global_quota;
|
||||
/** limit on validator validation attempts. */
|
||||
int val_validation_attempts;
|
||||
/** limit on validator hash attempts. */
|
||||
int val_hash_attempts;
|
||||
/** Should the iterator scrub promiscuous NS rrsets, from positive
|
||||
* answers. */
|
||||
int iter_scrub_promiscuous;
|
||||
|
||||
@@ -608,6 +608,8 @@ iter-scrub-ns{COLON} { YDVAR(1, VAR_ITER_SCRUB_NS) }
|
||||
iter-scrub-cname{COLON} { YDVAR(1, VAR_ITER_SCRUB_CNAME) }
|
||||
iter-scrub-rrsig{COLON} { YDVAR(1, VAR_ITER_SCRUB_RRSIG) }
|
||||
max-global-quota{COLON} { YDVAR(1, VAR_MAX_GLOBAL_QUOTA) }
|
||||
val-validation-attempts{COLON} { YDVAR(1, VAR_VAL_VALIDATION_ATTEMPTS) }
|
||||
val-hash-attempts{COLON} { YDVAR(1, VAR_VAL_HASH_ATTEMPTS) }
|
||||
max-transfer-size{COLON} { YDVAR(1, VAR_MAX_TRANSFER_SIZE) }
|
||||
max-transfer-time{COLON} { YDVAR(1, VAR_MAX_TRANSFER_TIME) }
|
||||
iter-scrub-promiscuous{COLON} { YDVAR(1, VAR_ITER_SCRUB_PROMISCUOUS) }
|
||||
|
||||
+21
-1
@@ -218,6 +218,7 @@ extern struct config_parser_state* cfg_parser;
|
||||
%token VAR_ITER_SCRUB_RRSIG
|
||||
%token VAR_MAX_TRANSFER_SIZE VAR_MAX_TRANSFER_TIME
|
||||
%token VAR_MAX_GLOBAL_QUOTA VAR_HARDEN_UNVERIFIED_GLUE VAR_LOG_TIME_ISO
|
||||
%token VAR_VAL_VALIDATION_ATTEMPTS VAR_VAL_HASH_ATTEMPTS
|
||||
%token VAR_ITER_SCRUB_PROMISCUOUS VAR_LOG_THREAD_ID
|
||||
|
||||
%%
|
||||
@@ -360,7 +361,8 @@ content_server: server_num_threads | server_verbosity | server_port |
|
||||
server_harden_unknown_additional | server_disable_edns_do |
|
||||
server_log_destaddr | server_cookie_secret_file |
|
||||
server_iter_scrub_ns | server_iter_scrub_cname | server_max_global_quota |
|
||||
server_iter_scrub_rrsig |
|
||||
server_val_validation_attempts |
|
||||
server_val_hash_attempts | server_iter_scrub_rrsig |
|
||||
server_harden_unverified_glue | server_log_time_iso | server_iter_scrub_promiscuous
|
||||
;
|
||||
stub_clause: stubstart contents_stub
|
||||
@@ -4317,6 +4319,24 @@ server_iter_scrub_promiscuous: VAR_ITER_SCRUB_PROMISCUOUS STRING_ARG
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
server_val_validation_attempts: VAR_VAL_VALIDATION_ATTEMPTS STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_val_validation_attempts:%s)\n", $2));
|
||||
if(atoi($2) == 0 && strcmp($2, "0") != 0)
|
||||
yyerror("number expected");
|
||||
else cfg_parser->cfg->val_validation_attempts = atoi($2);
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
server_val_hash_attempts: VAR_VAL_HASH_ATTEMPTS STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_val_hash_attempts:%s)\n", $2));
|
||||
if(atoi($2) == 0 && strcmp($2, "0") != 0)
|
||||
yyerror("number expected");
|
||||
else cfg_parser->cfg->val_hash_attempts = atoi($2);
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
ipsetstart: VAR_IPSET
|
||||
{
|
||||
OUTYY(("\nP(ipset:)\n"));
|
||||
|
||||
+14
-7
@@ -192,34 +192,34 @@ pkt_dname_len(sldns_buffer* pkt)
|
||||
while(1) {
|
||||
/* read next label */
|
||||
if(sldns_buffer_remaining(pkt) < 1)
|
||||
return 0;
|
||||
goto fail;
|
||||
labellen = sldns_buffer_read_u8(pkt);
|
||||
if(LABEL_IS_PTR(labellen)) {
|
||||
/* compression ptr */
|
||||
uint16_t ptr;
|
||||
if(sldns_buffer_remaining(pkt) < 1)
|
||||
return 0;
|
||||
goto fail;
|
||||
ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt));
|
||||
if(ptrcount++ > MAX_COMPRESS_PTRS)
|
||||
return 0; /* loop! */
|
||||
goto fail; /* loop! */
|
||||
if(sldns_buffer_limit(pkt) <= ptr)
|
||||
return 0; /* out of bounds! */
|
||||
goto fail; /* out of bounds! */
|
||||
if(!endpos)
|
||||
endpos = sldns_buffer_position(pkt);
|
||||
sldns_buffer_set_position(pkt, ptr);
|
||||
} else {
|
||||
/* label contents */
|
||||
if(labellen > 0x3f)
|
||||
return 0; /* label too long */
|
||||
goto fail; /* label too long */
|
||||
len += 1 + labellen;
|
||||
if(len > LDNS_MAX_DOMAINLEN)
|
||||
return 0;
|
||||
goto fail;
|
||||
if(labellen == 0) {
|
||||
/* end of dname */
|
||||
break;
|
||||
}
|
||||
if(sldns_buffer_remaining(pkt) < labellen)
|
||||
return 0;
|
||||
goto fail;
|
||||
sldns_buffer_skip(pkt, (ssize_t)labellen);
|
||||
}
|
||||
}
|
||||
@@ -227,6 +227,13 @@ pkt_dname_len(sldns_buffer* pkt)
|
||||
sldns_buffer_set_position(pkt, endpos);
|
||||
|
||||
return len;
|
||||
fail:
|
||||
/* Restore the position on failure too: callers (rdata_copy) compute
|
||||
* the consumed field length from the buffer position and must not
|
||||
* see a partial walk of a name that failed to parse. */
|
||||
if(endpos)
|
||||
sldns_buffer_set_position(pkt, endpos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
+40
-5
@@ -248,6 +248,7 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
|
||||
sldns_pkt_section section)
|
||||
{
|
||||
uint16_t pkt_len;
|
||||
size_t tolen;
|
||||
uint32_t ttl;
|
||||
const sldns_rr_descriptor* desc;
|
||||
|
||||
@@ -293,9 +294,13 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
|
||||
(rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t)));
|
||||
/* insert decompressed size into rdata len stored in memory */
|
||||
/* -2 because rdatalen bytes are not included. */
|
||||
tolen = rr->size;
|
||||
if(tolen < 2)
|
||||
return 0;
|
||||
pkt_len = htons(rr->size - 2);
|
||||
memmove(to, &pkt_len, sizeof(uint16_t));
|
||||
to += 2;
|
||||
tolen -= 2;
|
||||
/* read packet rdata len */
|
||||
pkt_len = sldns_buffer_read_u16(pkt);
|
||||
if(sldns_buffer_remaining(pkt) < pkt_len)
|
||||
@@ -304,16 +309,29 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
|
||||
if(pkt_len > 0 && desc && desc->_dname_count > 0) {
|
||||
int count = (int)desc->_dname_count;
|
||||
int rdf = 0;
|
||||
size_t len;
|
||||
size_t oldpos;
|
||||
size_t len, dlen;
|
||||
size_t oldpos, newpos;
|
||||
/* decompress dnames. */
|
||||
while(pkt_len > 0 && count) {
|
||||
switch(desc->_wireformat[rdf]) {
|
||||
case LDNS_RDF_TYPE_DNAME:
|
||||
oldpos = sldns_buffer_position(pkt);
|
||||
dname_pkt_copy(pkt, to,
|
||||
dlen = pkt_dname_len(pkt);
|
||||
if(dlen == 0)
|
||||
return 0; /* malformed */
|
||||
if(dlen > tolen)
|
||||
return 0; /* alloc mismatch */
|
||||
newpos = sldns_buffer_position(pkt);
|
||||
if(oldpos > newpos)
|
||||
return 0; /* should have moved forward*/
|
||||
sldns_buffer_set_position(pkt, oldpos);
|
||||
dname_pkt_copy(pkt, to,
|
||||
sldns_buffer_current(pkt));
|
||||
to += pkt_dname_len(pkt);
|
||||
sldns_buffer_set_position(pkt, newpos);
|
||||
to += dlen;
|
||||
tolen -= dlen;
|
||||
if(sldns_buffer_position(pkt)-oldpos > pkt_len)
|
||||
return 0; /* malformed: walks diverged */
|
||||
pkt_len -= sldns_buffer_position(pkt)-oldpos;
|
||||
count--;
|
||||
len = 0;
|
||||
@@ -326,9 +344,12 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
|
||||
break;
|
||||
}
|
||||
if(len) {
|
||||
if(len > tolen)
|
||||
return 0; /* alloc mismatch */
|
||||
log_assert(len <= pkt_len);
|
||||
memmove(to, sldns_buffer_current(pkt), len);
|
||||
to += len;
|
||||
tolen -= len;
|
||||
sldns_buffer_skip(pkt, (ssize_t)len);
|
||||
pkt_len -= len;
|
||||
}
|
||||
@@ -336,8 +357,11 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
|
||||
}
|
||||
}
|
||||
/* copy remaining rdata */
|
||||
if(pkt_len > 0)
|
||||
if(pkt_len > 0) {
|
||||
if(pkt_len > tolen)
|
||||
return 0; /* alloc mismatch */
|
||||
memmove(to, sldns_buffer_current(pkt), pkt_len);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1115,6 +1139,17 @@ reply_all_rrsets_secure(struct reply_info* rep)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int reply_an_ns_rrsets_secure(struct reply_info* rep)
|
||||
{
|
||||
size_t i;
|
||||
for(i=0; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
|
||||
if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
|
||||
->security != sec_status_secure )
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct reply_info*
|
||||
parse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region,
|
||||
struct query_info* qi)
|
||||
|
||||
@@ -494,6 +494,9 @@ int reply_check_cname_chain(struct query_info* qinfo, struct reply_info* rep);
|
||||
*/
|
||||
int reply_all_rrsets_secure(struct reply_info* rep);
|
||||
|
||||
/** Check status of answer and authority section RRs. */
|
||||
int reply_an_ns_rrsets_secure(struct reply_info* rep);
|
||||
|
||||
/**
|
||||
* Find answer rrset in reply, the one matching qinfo. Follows CNAMEs, so the
|
||||
* result may have a different owner name.
|
||||
|
||||
@@ -141,6 +141,8 @@ fptr_whitelist_comm_timer(void (*fptr)(void*))
|
||||
#ifdef UB_ON_WINDOWS
|
||||
else if(fptr == &wsvc_cron_cb) return 1;
|
||||
#endif
|
||||
else if(fptr == &tcp_read_again_cb) return 1;
|
||||
else if(fptr == &tcp_more_read_again_cb) return 1;
|
||||
else if(fptr == &auth_xfer_timer) return 1;
|
||||
else if(fptr == &auth_xfer_probe_timer_callback) return 1;
|
||||
else if(fptr == &auth_xfer_transfer_timer_callback) return 1;
|
||||
|
||||
+86
-1
@@ -122,6 +122,10 @@
|
||||
#define NUM_UDP_PER_SELECT 1
|
||||
#endif
|
||||
|
||||
/** The number of TCP queries over a TCP connection, per read indication
|
||||
* from select. */
|
||||
#define NUM_TCP_PER_SELECT 100
|
||||
|
||||
/** timeout in millisec to wait for write to unblock, packets dropped after.*/
|
||||
#define SEND_BLOCKED_WAIT_TIMEOUT 200
|
||||
/** max number of times to wait for write to unblock, packets dropped after.*/
|
||||
@@ -3226,6 +3230,26 @@ static int http2_submit_settings(struct http2_session* h2_session)
|
||||
}
|
||||
#endif /* HAVE_NGHTTP2 */
|
||||
|
||||
/** Clear http2 stream mesh states */
|
||||
static void http2_session_clear_meshstate(struct http2_session* h2_session)
|
||||
{
|
||||
#ifdef HAVE_NGHTTP2
|
||||
/* Since the session gets closed, remove the mesh state references. */
|
||||
struct http2_stream* h2_stream;
|
||||
for(h2_stream = h2_session->first_stream; h2_stream;
|
||||
h2_stream = h2_stream->next) {
|
||||
if(h2_stream->mesh_state) {
|
||||
mesh_state_remove_reply(h2_stream->mesh,
|
||||
h2_stream->mesh_state, h2_session->c,
|
||||
h2_stream, NULL);
|
||||
h2_stream->mesh_state = NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)h2_session;
|
||||
#endif /* HAVE_NGHTTP2 */
|
||||
}
|
||||
|
||||
#ifdef HAVE_NGHTTP2
|
||||
/** Delete http2 stream. After session delete or stream close callback */
|
||||
static void http2_stream_delete(struct http2_session* h2_session,
|
||||
@@ -4621,6 +4645,10 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
|
||||
static int
|
||||
tcp_req_info_read_again(int fd, struct comm_point* c)
|
||||
{
|
||||
/* One event-loop visit drains at most this many pipelined queries;
|
||||
* the rest is re-queued, so that other file descriptors get
|
||||
* serviced in between. */
|
||||
int budget = NUM_TCP_PER_SELECT;
|
||||
while(c->tcp_req_info->read_again) {
|
||||
int r;
|
||||
c->tcp_req_info->read_again = 0;
|
||||
@@ -4637,6 +4665,16 @@ tcp_req_info_read_again(int fd, struct comm_point* c)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if(--budget <= 0 && c->tcp_req_info->read_again) {
|
||||
/* Defer the rest of the drain to the next loop turn.
|
||||
* This uses a zero delay timer. For TLS the undrained
|
||||
* remainder sits in OpenSSL's user-space buffer. */
|
||||
struct timeval tv;
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
verbose(VERB_ALGO, "Defer tcp_req_info read again");
|
||||
comm_timer_set(c->tcp_req_info->read_again_timer, &tv);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -4650,6 +4688,7 @@ tcp_more_read_again(int fd, struct comm_point* c)
|
||||
/* this continues until the read routines get EAGAIN or so,
|
||||
* and thus does not call the callback, and the bool is 0 */
|
||||
int* moreread = c->tcp_more_read_again;
|
||||
int budget = NUM_TCP_PER_SELECT;
|
||||
while(moreread && *moreread) {
|
||||
*moreread = 0;
|
||||
if(!comm_point_tcp_handle_read(fd, c, 0)) {
|
||||
@@ -4662,6 +4701,30 @@ tcp_more_read_again(int fd, struct comm_point* c)
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(--budget <= 0 && *moreread) {
|
||||
/* Defer the rest of the drain to the next loop turn.
|
||||
* This uses a zero delay timer. For TLS the undrained
|
||||
* remainder sits in OpenSSL's user-space buffer. */
|
||||
struct timeval tv;
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
if(!c->tcp_more_read_again_timer) {
|
||||
c->tcp_more_read_again_timer = comm_timer_create(c->ev->base, tcp_more_read_again_cb, c);
|
||||
if(!c->tcp_more_read_again_timer) {
|
||||
log_err("out of memory for tcp more read again timer");
|
||||
reclaim_tcp_handler(c);
|
||||
if(!c->tcp_do_close) {
|
||||
fptr_ok(fptr_whitelist_comm_point(
|
||||
c->callback));
|
||||
(void)(*c->callback)(c, c->cb_arg,
|
||||
NETEVENT_CLOSED, NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
verbose(VERB_ALGO, "Defer more read again");
|
||||
comm_timer_set(c->tcp_more_read_again_timer, &tv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4689,6 +4752,23 @@ tcp_more_write_again(int fd, struct comm_point* c)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tcp_read_again_cb(void* arg)
|
||||
{
|
||||
struct tcp_req_info* req = (struct tcp_req_info*)arg;
|
||||
verbose(VERB_ALGO, "tcp_read_again_cb");
|
||||
if(!tcp_req_info_read_again(req->cp->fd, req->cp))
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
tcp_more_read_again_cb(void* arg)
|
||||
{
|
||||
struct comm_point* c = (struct comm_point*)arg;
|
||||
verbose(VERB_ALGO, "tcp_more_read_again_cb");
|
||||
tcp_more_read_again(c->fd, c);
|
||||
}
|
||||
|
||||
void
|
||||
comm_point_tcp_handle_callback(int fd, short event, void* arg)
|
||||
{
|
||||
@@ -6131,7 +6211,7 @@ comm_point_create_tcp_handler(struct comm_base *base,
|
||||
c->pp2_enabled = parent->pp2_enabled;
|
||||
c->pp2_header_state = pp2_header_none;
|
||||
if(spoolbuf) {
|
||||
c->tcp_req_info = tcp_req_info_create(spoolbuf);
|
||||
c->tcp_req_info = tcp_req_info_create(base, spoolbuf);
|
||||
if(!c->tcp_req_info) {
|
||||
log_err("could not create tcp commpoint");
|
||||
sldns_buffer_free(c->buffer);
|
||||
@@ -6693,6 +6773,9 @@ comm_point_close(struct comm_point* c)
|
||||
*c->tcp_more_read_again = 0;
|
||||
if(c->tcp_more_write_again && *c->tcp_more_write_again)
|
||||
*c->tcp_more_write_again = 0;
|
||||
if(c->tcp_more_read_again_timer &&
|
||||
comm_timer_is_set(c->tcp_more_read_again_timer))
|
||||
comm_timer_disable(c->tcp_more_read_again_timer);
|
||||
|
||||
/* close fd after removing from event lists, or epoll.. is messed up */
|
||||
if(c->fd != -1 && !c->do_not_close) {
|
||||
@@ -6732,6 +6815,7 @@ comm_point_delete(struct comm_point* c)
|
||||
free(c->tcp_handlers);
|
||||
}
|
||||
free(c->timeout);
|
||||
comm_timer_delete(c->tcp_more_read_again_timer);
|
||||
if(c->type == comm_tcp || c->type == comm_local || c->type == comm_http) {
|
||||
sldns_buffer_free(c->buffer);
|
||||
#ifdef USE_DNSCRYPT
|
||||
@@ -6872,6 +6956,7 @@ comm_point_drop_reply(struct comm_reply* repinfo)
|
||||
if(repinfo->c->type == comm_http) {
|
||||
if(repinfo->c->h2_session) {
|
||||
repinfo->c->h2_session->is_drop = 1;
|
||||
http2_session_clear_meshstate(repinfo->c->h2_session);
|
||||
if(!repinfo->c->h2_session->postpone_drop)
|
||||
reclaim_http_handler(repinfo->c);
|
||||
return;
|
||||
|
||||
@@ -384,6 +384,9 @@ struct comm_point {
|
||||
* Or leave NULL if it is not used at all. */
|
||||
int* tcp_more_write_again;
|
||||
|
||||
/** resume timer for tcp_more_read_again */
|
||||
struct comm_timer* tcp_more_read_again_timer;
|
||||
|
||||
/** if set, read/write completes:
|
||||
read/write state of tcp is toggled.
|
||||
buffer reset/bytecount reset.
|
||||
@@ -1133,6 +1136,12 @@ void doq_send_pkt(struct comm_point* c, struct doq_pkt_addr* paddr,
|
||||
/** doq timer callback function. */
|
||||
void doq_timer_cb(void* arg);
|
||||
|
||||
/** tcp read again callback function. For tcp req info listen. */
|
||||
void tcp_read_again_cb(void* arg);
|
||||
|
||||
/** tcp more read again callback function. For outside network. */
|
||||
void tcp_more_read_again_cb(void* arg);
|
||||
|
||||
/**
|
||||
* This routine is published for checks and tests, and is only used internally.
|
||||
* handle libevent callback for timer comm.
|
||||
|
||||
+13
-9
@@ -1297,12 +1297,13 @@ void autr_write_file(struct module_env* env, struct trust_anchor* tp)
|
||||
* @param tp: trust point to verify with
|
||||
* @param rrset: DNSKEY rrset to verify.
|
||||
* @param qstate: qstate with region.
|
||||
* @param vq: validator query state.
|
||||
* @return false on failure, true if verification successful.
|
||||
*/
|
||||
static int
|
||||
verify_dnskey(struct module_env* env, struct val_env* ve,
|
||||
struct trust_anchor* tp, struct ub_packed_rrset_key* rrset,
|
||||
struct module_qstate* qstate)
|
||||
struct module_qstate* qstate, struct val_qstate* vq)
|
||||
{
|
||||
char reasonbuf[256];
|
||||
char* reason = NULL;
|
||||
@@ -1310,7 +1311,7 @@ verify_dnskey(struct module_env* env, struct val_env* ve,
|
||||
int downprot = env->cfg->harden_algo_downgrade;
|
||||
enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset,
|
||||
tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason,
|
||||
NULL, qstate, reasonbuf, sizeof(reasonbuf));
|
||||
NULL, qstate, vq, reasonbuf, sizeof(reasonbuf));
|
||||
/* sigalg is ignored, it returns algorithms signalled to exist, but
|
||||
* in 5011 there are no other rrsets to check. if downprot is
|
||||
* enabled, then it checks that the DNSKEY is signed with all
|
||||
@@ -1350,16 +1351,18 @@ min_expiry(struct module_env* env, struct packed_rrset_data* dd)
|
||||
static int
|
||||
rr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve,
|
||||
struct ub_packed_rrset_key* dnskey_rrset, size_t i,
|
||||
struct module_qstate* qstate)
|
||||
struct module_qstate* qstate, struct val_qstate* vq)
|
||||
{
|
||||
enum sec_status sec;
|
||||
char* reason = NULL;
|
||||
size_t num_tagmatches = 0;
|
||||
verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d",
|
||||
(int)i);
|
||||
/* no algorithm downgrade protection necessary, if it is selfsigned
|
||||
* revoked it can be removed. */
|
||||
sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i,
|
||||
&reason, NULL, LDNS_SECTION_ANSWER, qstate);
|
||||
&reason, NULL, LDNS_SECTION_ANSWER, qstate, vq,
|
||||
&num_tagmatches);
|
||||
return (sec == sec_status_secure);
|
||||
}
|
||||
|
||||
@@ -1575,7 +1578,7 @@ init_events(struct trust_anchor* tp)
|
||||
static void
|
||||
check_contains_revoked(struct module_env* env, struct val_env* ve,
|
||||
struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
|
||||
int* changed, struct module_qstate* qstate)
|
||||
int* changed, struct module_qstate* qstate, struct val_qstate* vq)
|
||||
{
|
||||
struct packed_rrset_data* dd = (struct packed_rrset_data*)
|
||||
dnskey_rrset->entry.data;
|
||||
@@ -1595,7 +1598,8 @@ check_contains_revoked(struct module_env* env, struct val_env* ve,
|
||||
}
|
||||
if(!ta)
|
||||
continue; /* key not found */
|
||||
if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i, qstate)) {
|
||||
if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i, qstate,
|
||||
vq)) {
|
||||
/* checked if there is an rrsig signed by this key. */
|
||||
/* same keytag, but stored can be revoked already, so
|
||||
* compare keytags, with +0 or +128(REVOKE flag) */
|
||||
@@ -2209,7 +2213,7 @@ autr_tp_remove(struct module_env* env, struct trust_anchor* tp,
|
||||
|
||||
int autr_process_prime(struct module_env* env, struct val_env* ve,
|
||||
struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
|
||||
struct module_qstate* qstate)
|
||||
struct module_qstate* qstate, struct val_qstate* vq)
|
||||
{
|
||||
int changed = 0;
|
||||
log_assert(tp && tp->autr);
|
||||
@@ -2250,7 +2254,7 @@ int autr_process_prime(struct module_env* env, struct val_env* ve,
|
||||
return 1; /* trust point exists */
|
||||
}
|
||||
/* check for revoked keys to remove immediately */
|
||||
check_contains_revoked(env, ve, tp, dnskey_rrset, &changed, qstate);
|
||||
check_contains_revoked(env, ve, tp, dnskey_rrset, &changed, qstate, vq);
|
||||
if(changed) {
|
||||
verbose(VERB_ALGO, "autotrust: revokedkeys, reassemble");
|
||||
if(!autr_assemble(tp)) {
|
||||
@@ -2266,7 +2270,7 @@ int autr_process_prime(struct module_env* env, struct val_env* ve,
|
||||
}
|
||||
}
|
||||
/* verify the dnskey rrset and see if it is valid. */
|
||||
if(!verify_dnskey(env, ve, tp, dnskey_rrset, qstate)) {
|
||||
if(!verify_dnskey(env, ve, tp, dnskey_rrset, qstate, vq)) {
|
||||
verbose(VERB_ALGO, "autotrust: dnskey did not verify.");
|
||||
/* only increase failure count if this is not the first prime,
|
||||
* this means there was a previous successful probe */
|
||||
|
||||
@@ -50,6 +50,7 @@ struct module_env;
|
||||
struct module_qstate;
|
||||
struct val_env;
|
||||
struct sldns_buffer;
|
||||
struct val_qstate;
|
||||
|
||||
/** Autotrust anchor states */
|
||||
typedef enum {
|
||||
@@ -190,13 +191,14 @@ void autr_point_delete(struct trust_anchor* tp);
|
||||
* @param dnskey_rrset: DNSKEY rrset probed (can be NULL if bad prime result).
|
||||
* allocated in a region. Has not been validated yet.
|
||||
* @param qstate: qstate with region.
|
||||
* @param vq: validator query state.
|
||||
* @return false if trust anchor was revoked completely.
|
||||
* Otherwise logs errors to log, does not change return value.
|
||||
* On errors, likely the trust point has been unchanged.
|
||||
*/
|
||||
int autr_process_prime(struct module_env* env, struct val_env* ve,
|
||||
struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
|
||||
struct module_qstate* qstate);
|
||||
struct module_qstate* qstate, struct val_qstate* vq);
|
||||
|
||||
/**
|
||||
* Debug printout of rfc5011 tracked anchors
|
||||
|
||||
@@ -177,7 +177,8 @@ static int
|
||||
nsec_verify_rrset(struct module_env* env, struct val_env* ve,
|
||||
struct ub_packed_rrset_key* nsec, struct key_entry_key* kkey,
|
||||
char** reason, sldns_ede_code* reason_bogus,
|
||||
struct module_qstate* qstate, char* reasonbuf, size_t reasonlen)
|
||||
struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf,
|
||||
size_t reasonlen)
|
||||
{
|
||||
struct packed_rrset_data* d = (struct packed_rrset_data*)
|
||||
nsec->entry.data;
|
||||
@@ -189,7 +190,7 @@ nsec_verify_rrset(struct module_env* env, struct val_env* ve,
|
||||
if(d->security == sec_status_secure)
|
||||
return 1;
|
||||
d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason,
|
||||
reason_bogus, LDNS_SECTION_AUTHORITY, qstate, &verified,
|
||||
reason_bogus, LDNS_SECTION_AUTHORITY, qstate, vq, &verified,
|
||||
reasonbuf, reasonlen);
|
||||
if(d->security == sec_status_secure) {
|
||||
rrset_update_sec_status(env->rrset_cache, nsec, *env->now);
|
||||
@@ -203,7 +204,7 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve,
|
||||
struct query_info* qinfo, struct reply_info* rep,
|
||||
struct key_entry_key* kkey, time_t* proof_ttl, char** reason,
|
||||
sldns_ede_code* reason_bogus, struct module_qstate* qstate,
|
||||
char* reasonbuf, size_t reasonlen)
|
||||
struct val_qstate* vq, char* reasonbuf, size_t reasonlen)
|
||||
{
|
||||
struct ub_packed_rrset_key* nsec = reply_find_rrset_section_ns(
|
||||
rep, qinfo->qname, qinfo->qname_len, LDNS_RR_TYPE_NSEC,
|
||||
@@ -221,7 +222,7 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve,
|
||||
* 2) this is not a delegation point */
|
||||
if(nsec) {
|
||||
if(!nsec_verify_rrset(env, ve, nsec, kkey, reason,
|
||||
reason_bogus, qstate, reasonbuf, reasonlen)) {
|
||||
reason_bogus, qstate, vq, reasonbuf, reasonlen)) {
|
||||
verbose(VERB_ALGO, "NSEC RRset for the "
|
||||
"referral did not verify.");
|
||||
return sec_status_bogus;
|
||||
@@ -258,7 +259,7 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve,
|
||||
if(rep->rrsets[i]->rk.type != htons(LDNS_RR_TYPE_NSEC))
|
||||
continue;
|
||||
if(!nsec_verify_rrset(env, ve, rep->rrsets[i], kkey, reason,
|
||||
reason_bogus, qstate, reasonbuf, reasonlen)) {
|
||||
reason_bogus, qstate, vq, reasonbuf, reasonlen)) {
|
||||
verbose(VERB_ALGO, "NSEC for empty non-terminal "
|
||||
"did not verify.");
|
||||
*reason = "NSEC for empty non-terminal "
|
||||
|
||||
@@ -52,6 +52,7 @@ struct ub_packed_rrset_key;
|
||||
struct reply_info;
|
||||
struct query_info;
|
||||
struct key_entry_key;
|
||||
struct val_qstate;
|
||||
|
||||
/**
|
||||
* Check DS absence.
|
||||
@@ -68,6 +69,7 @@ struct key_entry_key;
|
||||
* @param reason: string explaining why bogus.
|
||||
* @param reason_bogus: relevant EDE code for validation failure.
|
||||
* @param qstate: qstate with region.
|
||||
* @param vq: validator qstate.
|
||||
* @param reasonbuf: buffer to use for fail reason string print.
|
||||
* @param reasonlen: length of reasonbuf.
|
||||
* @return security status.
|
||||
@@ -80,7 +82,8 @@ enum sec_status val_nsec_prove_nodata_dsreply(struct module_env* env,
|
||||
struct val_env* ve, struct query_info* qinfo,
|
||||
struct reply_info* rep, struct key_entry_key* kkey,
|
||||
time_t* proof_ttl, char** reason, sldns_ede_code* reason_bogus,
|
||||
struct module_qstate* qstate, char* reasonbuf, size_t reasonlen);
|
||||
struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf,
|
||||
size_t reasonlen);
|
||||
|
||||
/**
|
||||
* nsec typemap check, takes an NSEC-type bitmap as argument, checks for type.
|
||||
|
||||
@@ -1521,7 +1521,8 @@ static int
|
||||
list_is_secure(struct module_env* env, struct val_env* ve,
|
||||
struct ub_packed_rrset_key** list, size_t num,
|
||||
struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus,
|
||||
struct module_qstate* qstate, char* reasonbuf, size_t reasonlen)
|
||||
struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf,
|
||||
size_t reasonlen)
|
||||
{
|
||||
struct packed_rrset_data* d;
|
||||
size_t i;
|
||||
@@ -1537,7 +1538,7 @@ list_is_secure(struct module_env* env, struct val_env* ve,
|
||||
continue;
|
||||
d->security = val_verify_rrset_entry(env, ve, list[i], kkey,
|
||||
reason, reason_bogus, LDNS_SECTION_AUTHORITY, qstate,
|
||||
&verified, reasonbuf, reasonlen);
|
||||
vq, &verified, reasonbuf, reasonlen);
|
||||
if(d->security != sec_status_secure) {
|
||||
verbose(VERB_ALGO, "NSEC3 did not verify");
|
||||
return 0;
|
||||
@@ -1552,7 +1553,8 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
|
||||
struct ub_packed_rrset_key** list, size_t num,
|
||||
struct query_info* qinfo, struct key_entry_key* kkey, char** reason,
|
||||
sldns_ede_code* reason_bogus, struct module_qstate* qstate,
|
||||
struct nsec3_cache_table* ct, char* reasonbuf, size_t reasonlen)
|
||||
struct val_qstate* vq, struct nsec3_cache_table* ct, char* reasonbuf,
|
||||
size_t reasonlen)
|
||||
{
|
||||
struct nsec3_filter flt;
|
||||
struct ce_response ce;
|
||||
@@ -1568,7 +1570,7 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
|
||||
return sec_status_bogus; /* no valid NSEC3s, bogus */
|
||||
}
|
||||
if(!list_is_secure(env, ve, list, num, kkey, reason, reason_bogus,
|
||||
qstate, reasonbuf, reasonlen)) {
|
||||
qstate, vq, reasonbuf, reasonlen)) {
|
||||
*reason = "not all NSEC3 records secure";
|
||||
return sec_status_bogus; /* not all NSEC3 records secure */
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ struct reply_info;
|
||||
struct query_info;
|
||||
struct key_entry_key;
|
||||
struct sldns_buffer;
|
||||
struct val_qstate;
|
||||
|
||||
/**
|
||||
* 0 1 2 3 4 5 6 7
|
||||
@@ -215,6 +216,7 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve,
|
||||
* @param reason: string for bogus result.
|
||||
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
|
||||
* @param qstate: qstate with region.
|
||||
* @param vq: validator qstate.
|
||||
* @param ct: cached hashes table.
|
||||
* @param reasonbuf: buffer to use for fail reason string print.
|
||||
* @param reasonlen: length of reasonbuf.
|
||||
@@ -230,7 +232,8 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
|
||||
struct ub_packed_rrset_key** list, size_t num,
|
||||
struct query_info* qinfo, struct key_entry_key* kkey, char** reason,
|
||||
sldns_ede_code* reason_bogus, struct module_qstate* qstate,
|
||||
struct nsec3_cache_table* ct, char* reasonbuf, size_t reasonlen);
|
||||
struct val_qstate* vq, struct nsec3_cache_table* ct, char* reasonbuf,
|
||||
size_t reasonlen);
|
||||
|
||||
/**
|
||||
* Prove NXDOMAIN or NODATA.
|
||||
|
||||
+108
-8
@@ -82,6 +82,8 @@
|
||||
|
||||
/** Maximum number of RRSIG validations for an RRset. */
|
||||
#define MAX_VALIDATE_RRSIGS 8
|
||||
/** Maximum number of NSEC validations for a message. */
|
||||
#define MAX_VALIDATE_NSECS 8
|
||||
|
||||
/** return number of rrs in an rrset */
|
||||
static size_t
|
||||
@@ -305,6 +307,8 @@ ds_create_dnskey_digest(struct module_env* env,
|
||||
* digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA);
|
||||
* DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key. */
|
||||
sldns_buffer_clear(b);
|
||||
if(!sldns_buffer_available(b, dnskey_rrset->rk.dname_len + dnskey_len-2))
|
||||
return 0; /* buffer too small */
|
||||
sldns_buffer_write(b, dnskey_rrset->rk.dname,
|
||||
dnskey_rrset->rk.dname_len);
|
||||
query_dname_tolower(sldns_buffer_begin(b));
|
||||
@@ -546,8 +550,10 @@ int algo_needs_missing(struct algo_needs* n)
|
||||
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
|
||||
* @param section: section of packet where this rrset comes from.
|
||||
* @param qstate: qstate with region.
|
||||
* @param vq: validator qstate with attempt counts.
|
||||
* @param numverified: incremented when the number of RRSIG validations
|
||||
* increases.
|
||||
* @param num_tagmatches: incremented for tag matches.
|
||||
* @return secure if any key signs *this* signature. bogus if no key signs it,
|
||||
* unchecked on error, or indeterminate if all keys are not supported by
|
||||
* the crypto library (openssl3+ only).
|
||||
@@ -559,7 +565,7 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
|
||||
struct rbtree_type** sortree,
|
||||
char** reason, sldns_ede_code *reason_bogus,
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
int* numverified)
|
||||
struct val_qstate* vq, int* numverified, size_t* num_tagmatches)
|
||||
{
|
||||
/* find matching keys and check them */
|
||||
enum sec_status sec = sec_status_bogus;
|
||||
@@ -578,6 +584,14 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
|
||||
}
|
||||
|
||||
for(i=0; i<num; i++) {
|
||||
if((*num_tagmatches)++ > MAX_TAG_MATCHES) {
|
||||
*reason = "too many tag matches";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
verbose(VERB_ALGO, "verify sig: too many tag matches, "
|
||||
"MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES);
|
||||
return sec_status_bogus;
|
||||
}
|
||||
/* see if key matches keytag and algo */
|
||||
if(algo != dnskey_get_algo(dnskey, i) ||
|
||||
tag != dnskey_calc_keytag(dnskey, i))
|
||||
@@ -585,6 +599,26 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
|
||||
numchecked ++;
|
||||
(*numverified)++;
|
||||
|
||||
if(vq && vq->num_validation_attempts++ > env->cfg->val_validation_attempts) {
|
||||
*reason = "too many validation attempts";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
verbose(VERB_ALGO, "verify sig: too many validation attempts, "
|
||||
"val-validation-attempts (%d); bogus", env->cfg->val_validation_attempts);
|
||||
return sec_status_bogus;
|
||||
}
|
||||
if(vq && (ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC ||
|
||||
ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC3) &&
|
||||
vq->num_nsec_attempts++ > MAX_VALIDATE_NSECS) {
|
||||
*reason = "too many NSEC or NSEC3 validation attempts";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
verbose(VERB_ALGO, "verify sig: too many NSEC or NSEC3 validation attempts, "
|
||||
"(%d); bogus", MAX_VALIDATE_NSECS);
|
||||
vq->num_nsec_attempts_exceeded = 1;
|
||||
return sec_status_bogus;
|
||||
}
|
||||
|
||||
/* see if key verifies */
|
||||
sec = dnskey_verify_rrset_sig(env->scratch,
|
||||
env->scratch_buffer, ve, now, rrset, dnskey, i,
|
||||
@@ -624,11 +658,12 @@ enum sec_status
|
||||
dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
|
||||
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
|
||||
uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus,
|
||||
sldns_pkt_section section, struct module_qstate* qstate, int* verified,
|
||||
char* reasonbuf, size_t reasonlen)
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int* verified, char* reasonbuf,
|
||||
size_t reasonlen)
|
||||
{
|
||||
enum sec_status sec;
|
||||
size_t i, num;
|
||||
size_t i, num, num_tagmatches = 0;
|
||||
rbtree_type* sortree = NULL;
|
||||
/* make sure that for all DNSKEY algorithms there are valid sigs */
|
||||
struct algo_needs needs;
|
||||
@@ -656,9 +691,19 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
|
||||
}
|
||||
}
|
||||
for(i=0; i<num; i++) {
|
||||
if(num_tagmatches > MAX_TAG_MATCHES) {
|
||||
*reason = "too many tag matches";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
verbose(VERB_ALGO, "rrset failed to verify: too many tag matches, "
|
||||
"MAX_TAG_MATCHES (%d)", MAX_TAG_MATCHES);
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
return sec_status_bogus;
|
||||
}
|
||||
sec = dnskeyset_verify_rrset_sig(env, ve, *env->now, rrset,
|
||||
dnskey, i, &sortree, reason, reason_bogus,
|
||||
section, qstate, verified);
|
||||
section, qstate, vq, verified, &num_tagmatches);
|
||||
/* see which algorithm has been fixed up */
|
||||
if(sec == sec_status_secure) {
|
||||
if(!sigalg)
|
||||
@@ -707,7 +752,8 @@ enum sec_status
|
||||
dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
|
||||
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
|
||||
size_t dnskey_idx, char** reason, sldns_ede_code *reason_bogus,
|
||||
sldns_pkt_section section, struct module_qstate* qstate)
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, size_t* num_tagmatches)
|
||||
{
|
||||
enum sec_status sec;
|
||||
size_t i, num, numchecked = 0, numindeterminate = 0;
|
||||
@@ -728,9 +774,26 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
|
||||
}
|
||||
for(i=0; i<num; i++) {
|
||||
/* see if sig matches keytag and algo */
|
||||
if((*num_tagmatches)++ > MAX_TAG_MATCHES) {
|
||||
*reason = "too many tag matches";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
verbose(VERB_ALGO, "rrset failed to verify: too many tag matches, "
|
||||
"MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES);
|
||||
return sec_status_bogus;
|
||||
}
|
||||
if(algo != rrset_get_sig_algo(rrset, i) ||
|
||||
tag != rrset_get_sig_keytag(rrset, i))
|
||||
continue;
|
||||
if(vq && vq->num_validation_attempts++ > env->cfg->val_validation_attempts) {
|
||||
*reason = "too many validation attempts";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
verbose(VERB_ALGO, "rrset failed to verify: too many validation attempts, "
|
||||
"val-validation-attempts (%d); bogus", env->cfg->val_validation_attempts);
|
||||
return sec_status_bogus;
|
||||
}
|
||||
|
||||
buf_canon = 0;
|
||||
sec = dnskey_verify_rrset_sig(env->scratch,
|
||||
env->scratch_buffer, ve, *env->now, rrset,
|
||||
@@ -1308,15 +1371,32 @@ rrset_canonical(struct regional* region, sldns_buffer* buf,
|
||||
}
|
||||
|
||||
sldns_buffer_clear(buf);
|
||||
if(sldns_buffer_remaining(buf) < siglen || siglen < 18+1) {
|
||||
verbose(VERB_ALGO, "verify: failed to canonicalize, "
|
||||
"rrset too big");
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_write(buf, sig, siglen);
|
||||
/* canonicalize signer name */
|
||||
canon_dname_tolower(sldns_buffer_begin(buf)+18,
|
||||
sldns_buffer_current(buf));
|
||||
|
||||
if(sldns_buffer_remaining(buf) < k->rk.dname_len+2) {
|
||||
/* Check if the first can_owner name can fit in the buffer.
|
||||
* The length is k->rk.dname_len or k->rk.dname_len+2
|
||||
* if it has '*.' in prefixed. Checks the upper bound,
|
||||
* also realistically the rest of the rrtype, rrclass, origttl,
|
||||
* rdata and so on has to be inserted, so that extra space has
|
||||
* to be there. */
|
||||
verbose(VERB_ALGO, "verify: failed to canonicalize, "
|
||||
"rrset too big");
|
||||
return 0;
|
||||
}
|
||||
RBTREE_FOR(walk, struct canon_rr*, (*sortree)) {
|
||||
/* see if there is enough space left in the buffer */
|
||||
if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4
|
||||
+ d->rr_len[walk->rr_idx]) {
|
||||
log_err("verify: failed to canonicalize, "
|
||||
verbose(VERB_ALGO, "verify: failed to canonicalize, "
|
||||
"rrset too big");
|
||||
return 0;
|
||||
}
|
||||
@@ -1325,6 +1405,13 @@ rrset_canonical(struct regional* region, sldns_buffer* buf,
|
||||
sldns_buffer_write(buf, can_owner, can_owner_len);
|
||||
else insert_can_owner(buf, k, sig, &can_owner,
|
||||
&can_owner_len);
|
||||
/* Check again, if the rdata can fit in the buffer */
|
||||
if(sldns_buffer_remaining(buf) < 2 + 2 + 4
|
||||
+ d->rr_len[walk->rr_idx]) {
|
||||
verbose(VERB_ALGO, "verify: failed to canonicalize, "
|
||||
"rrset too big");
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_write(buf, &k->rk.type, 2);
|
||||
sldns_buffer_write(buf, &k->rk.rrset_class, 2);
|
||||
sldns_buffer_write(buf, sig+4, 4);
|
||||
@@ -1376,11 +1463,17 @@ rrset_canonicalize_to_buffer(struct regional* region, sldns_buffer* buf,
|
||||
canonical_sort(k, d, sortree, rrs);
|
||||
|
||||
sldns_buffer_clear(buf);
|
||||
if(sldns_buffer_remaining(buf) < k->rk.dname_len) {
|
||||
/* Check if the first can_owner name can fit in the buffer. */
|
||||
verbose(VERB_ALGO, "verify: failed to canonicalize, "
|
||||
"rrset too big");
|
||||
return 0;
|
||||
}
|
||||
RBTREE_FOR(walk, struct canon_rr*, sortree) {
|
||||
/* see if there is enough space left in the buffer */
|
||||
if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4
|
||||
+ d->rr_len[walk->rr_idx]) {
|
||||
log_err("verify: failed to canonicalize, "
|
||||
verbose(VERB_ALGO, "verify: failed to canonicalize, "
|
||||
"rrset too big");
|
||||
return 0;
|
||||
}
|
||||
@@ -1393,6 +1486,13 @@ rrset_canonicalize_to_buffer(struct regional* region, sldns_buffer* buf,
|
||||
query_dname_tolower(can_owner);
|
||||
can_owner_len = k->rk.dname_len;
|
||||
}
|
||||
/* Check again, if the rdata can fit in the buffer */
|
||||
if(sldns_buffer_remaining(buf) < 2 + 2 + 4
|
||||
+ d->rr_len[walk->rr_idx]) {
|
||||
verbose(VERB_ALGO, "verify: failed to canonicalize, "
|
||||
"rrset too big");
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_write(buf, &k->rk.type, 2);
|
||||
sldns_buffer_write(buf, &k->rk.rrset_class, 2);
|
||||
sldns_buffer_write_u32(buf, d->rr_ttl[walk->rr_idx]);
|
||||
|
||||
@@ -53,6 +53,7 @@ struct ub_packed_rrset_key;
|
||||
struct rbtree_type;
|
||||
struct regional;
|
||||
struct sldns_buffer;
|
||||
struct val_qstate;
|
||||
|
||||
/** number of entries in algorithm needs array */
|
||||
#define ALGO_NEEDS_MAX 256
|
||||
@@ -262,6 +263,7 @@ uint16_t dnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx);
|
||||
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
|
||||
* @param section: section of packet where this rrset comes from.
|
||||
* @param qstate: qstate with region.
|
||||
* @param vq: validator qstate with attempt counts.
|
||||
* @param verified: if not NULL the number of RRSIG validations is returned.
|
||||
* @param reasonbuf: buffer to use for fail reason string print.
|
||||
* @param reasonlen: length of reasonbuf.
|
||||
@@ -273,8 +275,9 @@ enum sec_status dnskeyset_verify_rrset(struct module_env* env,
|
||||
struct val_env* ve, struct ub_packed_rrset_key* rrset,
|
||||
struct ub_packed_rrset_key* dnskey, uint8_t* sigalg,
|
||||
char** reason, sldns_ede_code *reason_bogus,
|
||||
sldns_pkt_section section, struct module_qstate* qstate, int* verified,
|
||||
char* reasonbuf, size_t reasonlen);
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int* verified, char* reasonbuf,
|
||||
size_t reasonlen);
|
||||
|
||||
/**
|
||||
* verify rrset against one specific dnskey (from rrset)
|
||||
@@ -287,13 +290,16 @@ enum sec_status dnskeyset_verify_rrset(struct module_env* env,
|
||||
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
|
||||
* @param section: section of packet where this rrset comes from.
|
||||
* @param qstate: qstate with region.
|
||||
* @param vq: validator qstate with attempt counts.
|
||||
* @param num_tagmatches: incremented to keep track of tag matches.
|
||||
* @return secure if *this* key signs any of the signatures on rrset.
|
||||
* unchecked on error or and bogus on bad signature.
|
||||
*/
|
||||
enum sec_status dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
|
||||
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
|
||||
size_t dnskey_idx, char** reason, sldns_ede_code *reason_bogus,
|
||||
sldns_pkt_section section, struct module_qstate* qstate);
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, size_t* num_tagmatches);
|
||||
|
||||
/**
|
||||
* verify rrset, with specific dnskey(from set), for a specific rrsig
|
||||
|
||||
+86
-19
@@ -406,7 +406,8 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
|
||||
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys,
|
||||
uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus,
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
int *verified, char* reasonbuf, size_t reasonlen)
|
||||
struct val_qstate* vq, int *verified, char* reasonbuf,
|
||||
size_t reasonlen)
|
||||
{
|
||||
enum sec_status sec;
|
||||
struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
|
||||
@@ -431,7 +432,8 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
|
||||
log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname,
|
||||
ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
|
||||
sec = dnskeyset_verify_rrset(env, ve, rrset, keys, sigalg, reason,
|
||||
reason_bogus, section, qstate, verified, reasonbuf, reasonlen);
|
||||
reason_bogus, section, qstate, vq, verified, reasonbuf,
|
||||
reasonlen);
|
||||
verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec));
|
||||
regional_free_all(env->scratch);
|
||||
|
||||
@@ -475,7 +477,8 @@ val_verify_rrset_entry(struct module_env* env, struct val_env* ve,
|
||||
struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey,
|
||||
char** reason, sldns_ede_code *reason_bogus,
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
int* verified, char* reasonbuf, size_t reasonlen)
|
||||
struct val_qstate* vq, int* verified, char* reasonbuf,
|
||||
size_t reasonlen)
|
||||
{
|
||||
/* temporary dnskey rrset-key */
|
||||
struct ub_packed_rrset_key dnskey;
|
||||
@@ -489,7 +492,8 @@ val_verify_rrset_entry(struct module_env* env, struct val_env* ve,
|
||||
dnskey.entry.key = &dnskey;
|
||||
dnskey.entry.data = kd->rrset_data;
|
||||
sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason,
|
||||
reason_bogus, section, qstate, verified, reasonbuf, reasonlen);
|
||||
reason_bogus, section, qstate, vq, verified, reasonbuf,
|
||||
reasonlen);
|
||||
return sec;
|
||||
}
|
||||
|
||||
@@ -499,13 +503,20 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
|
||||
struct ub_packed_rrset_key* dnskey_rrset,
|
||||
struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason,
|
||||
sldns_ede_code *reason_bogus, struct module_qstate* qstate,
|
||||
int *nonechecked, char* reasonbuf, size_t reasonlen)
|
||||
struct val_qstate* vq, int *nonechecked, char* reasonbuf,
|
||||
size_t reasonlen, size_t* num_tagmatches,
|
||||
size_t* num_tagmatches_dnskeysig)
|
||||
{
|
||||
enum sec_status sec = sec_status_bogus;
|
||||
size_t i, num, numchecked = 0, numhashok = 0, numsizesupp = 0;
|
||||
num = rrset_get_count(dnskey_rrset);
|
||||
*nonechecked = 0;
|
||||
for(i=0; i<num; i++) {
|
||||
if((*num_tagmatches)++ > MAX_TAG_MATCHES) {
|
||||
verbose(VERB_ALGO, "DS match attempt reached "
|
||||
"MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES);
|
||||
return sec_status_bogus;
|
||||
}
|
||||
/* Skip DNSKEYs that don't match the basic criteria. */
|
||||
if(ds_get_key_algo(ds_rrset, ds_idx)
|
||||
!= dnskey_get_algo(dnskey_rrset, i)
|
||||
@@ -518,6 +529,15 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
|
||||
ds_get_key_algo(ds_rrset, ds_idx),
|
||||
ds_get_keytag(ds_rrset, ds_idx));
|
||||
|
||||
if(vq && vq->num_hash_attempts++ > env->cfg->val_hash_attempts) {
|
||||
*reason = "too many hash attempts";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
verbose(VERB_ALGO, "rrset failed to verify: too many hash attempts, "
|
||||
"val-hash-attempts (%d); bogus", env->cfg->val_hash_attempts);
|
||||
return sec_status_bogus;
|
||||
}
|
||||
|
||||
/* Convert the candidate DNSKEY into a hash using the
|
||||
* same DS hash algorithm. */
|
||||
if(!ds_digest_match_dnskey(env, dnskey_rrset, i, ds_rrset,
|
||||
@@ -541,8 +561,14 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
|
||||
|
||||
/* Otherwise, we have a match! Make sure that the DNSKEY
|
||||
* verifies *with this key* */
|
||||
if(*num_tagmatches_dnskeysig > MAX_TAG_MATCHES) {
|
||||
verbose(VERB_ALGO, "DS that matched has too many DNSKEY to RRSIG tag matches "
|
||||
"MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES);
|
||||
return sec_status_bogus;
|
||||
}
|
||||
sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset,
|
||||
i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate);
|
||||
i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate,
|
||||
vq, num_tagmatches_dnskeysig);
|
||||
if(sec == sec_status_secure) {
|
||||
return sec;
|
||||
}
|
||||
@@ -586,14 +612,14 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
|
||||
struct ub_packed_rrset_key* dnskey_rrset,
|
||||
struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason,
|
||||
sldns_ede_code *reason_bogus, struct module_qstate* qstate,
|
||||
char* reasonbuf, size_t reasonlen)
|
||||
struct val_qstate* vq, char* reasonbuf, size_t reasonlen)
|
||||
{
|
||||
/* as long as this is false, we can consider this DS rrset to be
|
||||
* equivalent to no DS rrset. */
|
||||
int has_useful_ds = 0, digest_algo, alg, has_algo_refusal = 0,
|
||||
nonechecked, has_checked_ds = 0;
|
||||
struct algo_needs needs;
|
||||
size_t i, num;
|
||||
size_t i, num, num_tagmatches = 0, num_tagmatches_dnskeysig = 0;
|
||||
enum sec_status sec;
|
||||
|
||||
if(dnskey_rrset->rk.dname_len != ds_rrset->rk.dname_len ||
|
||||
@@ -615,6 +641,13 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
|
||||
}
|
||||
num = rrset_get_count(ds_rrset);
|
||||
for(i=0; i<num; i++) {
|
||||
if(num_tagmatches > MAX_TAG_MATCHES) {
|
||||
verbose(VERB_ALGO, "DS verify attempt reached "
|
||||
"MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES);
|
||||
*reason = "DS verify has too many tag matches";
|
||||
return sec_status_bogus;
|
||||
}
|
||||
|
||||
/* Check to see if we can understand this DS.
|
||||
* And check it is the strongest digest */
|
||||
if(!ds_digest_algo_is_supported(ds_rrset, i) ||
|
||||
@@ -623,9 +656,16 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
|
||||
continue;
|
||||
}
|
||||
|
||||
if(num_tagmatches_dnskeysig > MAX_TAG_MATCHES) {
|
||||
verbose(VERB_ALGO, "DS verify attempt reached "
|
||||
"DNSKEY to RRSIG MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES);
|
||||
*reason = "DS verify has too many DNSKEY to RRSIG tag matches";
|
||||
return sec_status_bogus;
|
||||
}
|
||||
sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
|
||||
ds_rrset, i, reason, reason_bogus, qstate,
|
||||
&nonechecked, reasonbuf, reasonlen);
|
||||
ds_rrset, i, reason, reason_bogus, qstate, vq,
|
||||
&nonechecked, reasonbuf, reasonlen, &num_tagmatches,
|
||||
&num_tagmatches_dnskeysig);
|
||||
if(sec == sec_status_insecure) {
|
||||
/* DNSKEY too large unsupported or algo refused by
|
||||
* crypto lib. */
|
||||
@@ -687,12 +727,12 @@ val_verify_new_DNSKEYs(struct regional* region, struct module_env* env,
|
||||
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
|
||||
struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason,
|
||||
sldns_ede_code *reason_bogus, struct module_qstate* qstate,
|
||||
char* reasonbuf, size_t reasonlen)
|
||||
struct val_qstate* vq, char* reasonbuf, size_t reasonlen)
|
||||
{
|
||||
uint8_t sigalg[ALGO_NEEDS_MAX+1];
|
||||
enum sec_status sec = val_verify_DNSKEY_with_DS(env, ve,
|
||||
dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason,
|
||||
reason_bogus, qstate, reasonbuf, reasonlen);
|
||||
reason_bogus, qstate, vq, reasonbuf, reasonlen);
|
||||
|
||||
if(sec == sec_status_secure) {
|
||||
return key_entry_create_rrset(region,
|
||||
@@ -718,14 +758,14 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
|
||||
struct ub_packed_rrset_key* ta_ds,
|
||||
struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason,
|
||||
sldns_ede_code *reason_bogus, struct module_qstate* qstate,
|
||||
char* reasonbuf, size_t reasonlen)
|
||||
struct val_qstate* vq, char* reasonbuf, size_t reasonlen)
|
||||
{
|
||||
/* as long as this is false, we can consider this anchor to be
|
||||
* equivalent to no anchor. */
|
||||
int has_useful_ta = 0, digest_algo = 0, alg, has_algo_refusal = 0,
|
||||
nonechecked, has_checked_ds = 0;
|
||||
struct algo_needs needs;
|
||||
size_t i, num;
|
||||
size_t i, num, num_tagmatches = 0, num_tagmatches_dnskeysig = 0;
|
||||
enum sec_status sec;
|
||||
|
||||
if(ta_ds && (dnskey_rrset->rk.dname_len != ta_ds->rk.dname_len ||
|
||||
@@ -761,6 +801,15 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
|
||||
if(ta_ds) {
|
||||
num = rrset_get_count(ta_ds);
|
||||
for(i=0; i<num; i++) {
|
||||
if(num_tagmatches > MAX_TAG_MATCHES) {
|
||||
verbose(VERB_ALGO, "anchor DS verify attempt reached "
|
||||
"MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES);
|
||||
*reason = "anchor DS verify has too many tag matches";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
return sec_status_bogus;
|
||||
}
|
||||
|
||||
/* Check to see if we can understand this DS.
|
||||
* And check it is the strongest digest */
|
||||
if(!ds_digest_algo_is_supported(ta_ds, i) ||
|
||||
@@ -768,9 +817,18 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
|
||||
ds_get_digest_algo(ta_ds, i) != digest_algo)
|
||||
continue;
|
||||
|
||||
if(num_tagmatches_dnskeysig > MAX_TAG_MATCHES) {
|
||||
verbose(VERB_ALGO, "anchor DS verify has too many DNSKEY to RRSIG tag matches "
|
||||
"MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES);
|
||||
*reason = "anchor DS verify has too many DNSKEY to RRSIG tag matches";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
return sec_status_bogus;
|
||||
}
|
||||
sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
|
||||
ta_ds, i, reason, reason_bogus, qstate, &nonechecked,
|
||||
reasonbuf, reasonlen);
|
||||
ta_ds, i, reason, reason_bogus, qstate, vq,
|
||||
&nonechecked, reasonbuf, reasonlen, &num_tagmatches,
|
||||
&num_tagmatches_dnskeysig);
|
||||
if(sec == sec_status_insecure) {
|
||||
has_algo_refusal = 1;
|
||||
continue;
|
||||
@@ -813,8 +871,16 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
|
||||
/* we saw a useful TA */
|
||||
has_useful_ta = 1;
|
||||
|
||||
if(num_tagmatches_dnskeysig > MAX_TAG_MATCHES) {
|
||||
verbose(VERB_ALGO, "anchor DS that matched has too many DNSKEY to RRSIG tag matches "
|
||||
"MAX_TAG_MATCHES (%d); bogus", MAX_TAG_MATCHES);
|
||||
*reason = "anchor DS that matched has too many DNSKEY to RRSIG tag matches";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
return sec_status_bogus;
|
||||
}
|
||||
sec = dnskey_verify_rrset(env, ve, dnskey_rrset,
|
||||
ta_dnskey, i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate);
|
||||
ta_dnskey, i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate, vq, &num_tagmatches_dnskeysig);
|
||||
if(sec == sec_status_secure) {
|
||||
if(!sigalg || algo_needs_set_secure(&needs,
|
||||
(uint8_t)dnskey_get_algo(ta_dnskey, i))) {
|
||||
@@ -862,12 +928,13 @@ val_verify_new_DNSKEYs_with_ta(struct regional* region, struct module_env* env,
|
||||
struct ub_packed_rrset_key* ta_ds_rrset,
|
||||
struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot,
|
||||
char** reason, sldns_ede_code *reason_bogus,
|
||||
struct module_qstate* qstate, char* reasonbuf, size_t reasonlen)
|
||||
struct module_qstate* qstate, struct val_qstate* vq, char* reasonbuf,
|
||||
size_t reasonlen)
|
||||
{
|
||||
uint8_t sigalg[ALGO_NEEDS_MAX+1];
|
||||
enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve,
|
||||
dnskey_rrset, ta_ds_rrset, ta_dnskey_rrset,
|
||||
downprot?sigalg:NULL, reason, reason_bogus, qstate,
|
||||
downprot?sigalg:NULL, reason, reason_bogus, qstate, vq,
|
||||
reasonbuf, reasonlen);
|
||||
|
||||
if(sec == sec_status_secure) {
|
||||
|
||||
+16
-5
@@ -55,6 +55,11 @@ struct regional;
|
||||
struct val_anchors;
|
||||
struct rrset_cache;
|
||||
struct sock_list;
|
||||
struct val_qstate;
|
||||
|
||||
/** Maximum number of matches with key tag and algorithm, for DNSKEY to
|
||||
* RRSIG and DS to DNSKEY. Since the number is O(N*N), there is a limit. */
|
||||
#define MAX_TAG_MATCHES 256
|
||||
|
||||
/**
|
||||
* Response classifications for the validator. The different types of proofs.
|
||||
@@ -124,6 +129,7 @@ void val_find_signer(enum val_classification subtype,
|
||||
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
|
||||
* @param section: section of packet where this rrset comes from.
|
||||
* @param qstate: qstate with region.
|
||||
* @param vq: validator qstate with attempt counts.
|
||||
* @param verified: if not NULL, the number of RRSIG validations is returned.
|
||||
* @param reasonbuf: buffer to use for fail reason string print.
|
||||
* @param reasonlen: length of reasonbuf.
|
||||
@@ -133,7 +139,8 @@ enum sec_status val_verify_rrset_entry(struct module_env* env,
|
||||
struct val_env* ve, struct ub_packed_rrset_key* rrset,
|
||||
struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus,
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
int* verified, char* reasonbuf, size_t reasonlen);
|
||||
struct val_qstate* vq, int* verified, char* reasonbuf,
|
||||
size_t reasonlen);
|
||||
|
||||
/**
|
||||
* Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but
|
||||
@@ -148,6 +155,7 @@ enum sec_status val_verify_rrset_entry(struct module_env* env,
|
||||
* @param reason: reason of failure. Fixed string or alloced in scratch.
|
||||
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
|
||||
* @param qstate: qstate with region.
|
||||
* @param vq: validator qstate with attempt counts.
|
||||
* @param reasonbuf: buffer to use for fail reason string print.
|
||||
* @param reasonlen: length of reasonbuf.
|
||||
* @return: sec_status_secure if a DS matches.
|
||||
@@ -158,7 +166,7 @@ enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env,
|
||||
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
|
||||
struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason,
|
||||
sldns_ede_code *reason_bogus, struct module_qstate* qstate,
|
||||
char* reasonbuf, size_t reasonlen);
|
||||
struct val_qstate* vq, char* reasonbuf, size_t reasonlen);
|
||||
|
||||
/**
|
||||
* Verify DNSKEYs with DS and DNSKEY rrset. Like val_verify_DNSKEY_with_DS
|
||||
@@ -174,6 +182,7 @@ enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env,
|
||||
* @param reason: reason of failure. Fixed string or alloced in scratch.
|
||||
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
|
||||
* @param qstate: qstate with region.
|
||||
* @param vq: validator qstate with attempt counts.
|
||||
* @param reasonbuf: buffer to use for fail reason string print.
|
||||
* @param reasonlen: length of reasonbuf.
|
||||
* @return: sec_status_secure if a DS matches.
|
||||
@@ -185,7 +194,7 @@ enum sec_status val_verify_DNSKEY_with_TA(struct module_env* env,
|
||||
struct ub_packed_rrset_key* ta_ds,
|
||||
struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason,
|
||||
sldns_ede_code *reason_bogus, struct module_qstate* qstate,
|
||||
char* reasonbuf, size_t reasonlen);
|
||||
struct val_qstate* vq, char* reasonbuf, size_t reasonlen);
|
||||
|
||||
/**
|
||||
* Verify new DNSKEYs with DS rrset. The DS contains hash values that should
|
||||
@@ -202,6 +211,7 @@ enum sec_status val_verify_DNSKEY_with_TA(struct module_env* env,
|
||||
* @param reason: reason of failure. Fixed string or alloced in scratch.
|
||||
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
|
||||
* @param qstate: qstate with region.
|
||||
* @param vq: validator qstate with attempt counts.
|
||||
* @param reasonbuf: buffer to use for fail reason string print.
|
||||
* @param reasonlen: length of reasonbuf.
|
||||
* @return a KeyEntry. This will either contain the now trusted
|
||||
@@ -219,7 +229,7 @@ struct key_entry_key* val_verify_new_DNSKEYs(struct regional* region,
|
||||
struct ub_packed_rrset_key* dnskey_rrset,
|
||||
struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason,
|
||||
sldns_ede_code *reason_bogus, struct module_qstate* qstate,
|
||||
char* reasonbuf, size_t reasonlen);
|
||||
struct val_qstate* vq, char* reasonbuf, size_t reasonlen);
|
||||
|
||||
/**
|
||||
* Verify rrset with trust anchor: DS and DNSKEY rrset.
|
||||
@@ -235,6 +245,7 @@ struct key_entry_key* val_verify_new_DNSKEYs(struct regional* region,
|
||||
* @param reason: reason of failure. Fixed string or alloced in scratch.
|
||||
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
|
||||
* @param qstate: qstate with region.
|
||||
* @param vq: validator qstate with attempt counts.
|
||||
* @param reasonbuf: buffer to use for fail reason string print.
|
||||
* @param reasonlen: length of reasonbuf.
|
||||
* @return a KeyEntry. This will either contain the now trusted
|
||||
@@ -253,7 +264,7 @@ struct key_entry_key* val_verify_new_DNSKEYs_with_ta(struct regional* region,
|
||||
struct ub_packed_rrset_key* ta_ds_rrset,
|
||||
struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot,
|
||||
char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate,
|
||||
char* reasonbuf, size_t reasonlen);
|
||||
struct val_qstate* vq, char* reasonbuf, size_t reasonlen);
|
||||
|
||||
/**
|
||||
* Determine if DS rrset is usable for validator or not.
|
||||
|
||||
+75
-34
@@ -350,13 +350,17 @@ static void
|
||||
val_restart(struct val_qstate* vq)
|
||||
{
|
||||
struct comm_timer* temp_timer;
|
||||
int restart_count;
|
||||
int restart_count, num_validation_attempts, num_hash_attempts;
|
||||
if(!vq) return;
|
||||
temp_timer = vq->suspend_timer;
|
||||
restart_count = vq->restart_count+1;
|
||||
num_validation_attempts = vq->num_validation_attempts;
|
||||
num_hash_attempts = vq->num_hash_attempts;
|
||||
memset(vq, 0, sizeof(*vq));
|
||||
vq->suspend_timer = temp_timer;
|
||||
vq->restart_count = restart_count;
|
||||
vq->num_validation_attempts = num_validation_attempts;
|
||||
vq->num_hash_attempts = num_hash_attempts;
|
||||
vq->state = VAL_INIT_STATE;
|
||||
}
|
||||
|
||||
@@ -455,6 +459,24 @@ already_validated(struct dns_msg* ret_msg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** If it is possible to restart the validation state */
|
||||
static int
|
||||
val_can_restart(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
struct val_env* ve)
|
||||
{
|
||||
/* For validation failures that are limits exceeded on the amount
|
||||
* of work that the DNSSEC validator is willing to do, the restart
|
||||
* is not allowed. A restart would increase the amount of effort
|
||||
* spent even further. */
|
||||
if(vq->restart_count < ve->max_restart &&
|
||||
vq->num_validation_attempts <= qstate->env->cfg->val_validation_attempts &&
|
||||
vq->num_hash_attempts <= qstate->env->cfg->val_hash_attempts &&
|
||||
!vq->num_nsec_attempts_exceeded)
|
||||
return 1;
|
||||
(void)qstate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a request for DNS data.
|
||||
*
|
||||
@@ -763,8 +785,8 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
|
||||
/* Verify the answer rrset */
|
||||
sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
|
||||
&reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified,
|
||||
reasonbuf, sizeof(reasonbuf));
|
||||
&reason_bogus, LDNS_SECTION_ANSWER, qstate, vq,
|
||||
&verified, reasonbuf, sizeof(reasonbuf));
|
||||
/* If the (answer) rrset failed to validate, then this
|
||||
* message is BAD. */
|
||||
if(sec != sec_status_secure) {
|
||||
@@ -808,7 +830,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
continue;
|
||||
s = chase_reply->rrsets[i];
|
||||
sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
|
||||
&reason_bogus, LDNS_SECTION_AUTHORITY, qstate,
|
||||
&reason_bogus, LDNS_SECTION_AUTHORITY, qstate, vq,
|
||||
&verified, reasonbuf, sizeof(reasonbuf));
|
||||
/* If anything in the authority section fails to be secure,
|
||||
* we have a bad message. */
|
||||
@@ -855,7 +877,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
if(sname && query_dname_compare(sname, key_entry->name)==0)
|
||||
(void)val_verify_rrset_entry(env, ve, s, key_entry,
|
||||
&reason, NULL, LDNS_SECTION_ADDITIONAL, qstate,
|
||||
&verified, reasonbuf, sizeof(reasonbuf));
|
||||
vq, &verified, reasonbuf, sizeof(reasonbuf));
|
||||
/* the additional section can fail to be secure,
|
||||
* it is optional, check signature in case we need
|
||||
* to clean the additional section later. */
|
||||
@@ -1433,16 +1455,20 @@ validate_nameerror_response(struct module_env* env, struct val_env* ve,
|
||||
* trusted DNSKEY rrset that signs this response must already have been
|
||||
* completed.
|
||||
*
|
||||
* @param env: module env.
|
||||
* @param chase_reply: answer to validate.
|
||||
*/
|
||||
static void
|
||||
validate_referral_response(struct reply_info* chase_reply)
|
||||
validate_referral_response(struct module_env* env, struct reply_info* chase_reply)
|
||||
{
|
||||
size_t i;
|
||||
size_t i, count;
|
||||
enum sec_status s;
|
||||
/* message security equals lowest rrset security */
|
||||
chase_reply->security = sec_status_secure;
|
||||
for(i=0; i<chase_reply->rrset_count; i++) {
|
||||
if(env->cfg->val_clean_additional)
|
||||
count = chase_reply->rrset_count;
|
||||
else count = chase_reply->an_numrrsets+chase_reply->ns_numrrsets;
|
||||
for(i=0; i<count; i++) {
|
||||
s = ((struct packed_rrset_data*)chase_reply->rrsets[i]
|
||||
->entry.data)->security;
|
||||
if(s < chase_reply->security)
|
||||
@@ -2309,7 +2335,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
key_entry_get_reason_bogus(vq->key_entry));
|
||||
errinf_ede(qstate, "while building chain of trust",
|
||||
key_entry_get_reason_bogus(vq->key_entry));
|
||||
if(vq->restart_count >= ve->max_restart)
|
||||
if(!val_can_restart(qstate, vq, ve))
|
||||
key_cache_insert(ve->kcache, vq->key_entry,
|
||||
qstate->env->cfg->val_log_level >= 2);
|
||||
return 1;
|
||||
@@ -2457,7 +2483,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
|
||||
case VAL_CLASS_REFERRAL:
|
||||
verbose(VERB_ALGO, "Validating a referral response");
|
||||
validate_referral_response(vq->chase_reply);
|
||||
validate_referral_response(qstate->env, vq->chase_reply);
|
||||
verbose(VERB_DETAIL, "validate(referral): %s",
|
||||
sec_status_to_string(
|
||||
vq->chase_reply->security));
|
||||
@@ -2531,15 +2557,17 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
}
|
||||
|
||||
if(subtype == VAL_CLASS_REFERRAL) {
|
||||
/* for a referral, move to next unchecked rrset and check it*/
|
||||
vq->rrset_skip = val_next_unchecked(vq->orig_msg->rep,
|
||||
vq->rrset_skip);
|
||||
if(vq->rrset_skip < vq->orig_msg->rep->rrset_count) {
|
||||
/* and restart for this rrset */
|
||||
verbose(VERB_ALGO, "validator: go to next rrset");
|
||||
vq->chase_reply->security = sec_status_unchecked;
|
||||
vq->state = VAL_INIT_STATE;
|
||||
return 1;
|
||||
if(qstate->env->cfg->val_clean_additional) {
|
||||
/* for a referral, move to next unchecked rrset and check it*/
|
||||
vq->rrset_skip = val_next_unchecked(vq->orig_msg->rep,
|
||||
vq->rrset_skip);
|
||||
if(vq->rrset_skip < vq->orig_msg->rep->rrset_count) {
|
||||
/* and restart for this rrset */
|
||||
verbose(VERB_ALGO, "validator: go to next rrset");
|
||||
vq->chase_reply->security = sec_status_unchecked;
|
||||
vq->state = VAL_INIT_STATE;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* referral chase is done */
|
||||
}
|
||||
@@ -2584,7 +2612,7 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
struct msgreply_entry* e;
|
||||
|
||||
/* see if we can try again to fetch data */
|
||||
if(vq->restart_count < ve->max_restart) {
|
||||
if(val_can_restart(qstate, vq, ve)) {
|
||||
verbose(VERB_ALGO, "validation failed, "
|
||||
"blacklist and retry to fetch data");
|
||||
val_blacklist(&qstate->blacklist, qstate->region,
|
||||
@@ -2876,6 +2904,7 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
* (this rrset is allocated in the wrong region, not the qstate).
|
||||
* @param ta: trust anchor.
|
||||
* @param qstate: qstate that needs key.
|
||||
* @param vq: validator qstate.
|
||||
* @param id: module id.
|
||||
* @param sub_qstate: the sub query state, that is the lookup that fetched
|
||||
* the trust anchor data, it contains error information for the answer.
|
||||
@@ -2886,8 +2915,8 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
*/
|
||||
static struct key_entry_key*
|
||||
primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
|
||||
struct trust_anchor* ta, struct module_qstate* qstate, int id,
|
||||
struct module_qstate* sub_qstate)
|
||||
struct trust_anchor* ta, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int id, struct module_qstate* sub_qstate)
|
||||
{
|
||||
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
|
||||
struct key_entry_key* kkey = NULL;
|
||||
@@ -2927,7 +2956,8 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
|
||||
/* attempt to verify with trust anchor DS and DNSKEY */
|
||||
kkey = val_verify_new_DNSKEYs_with_ta(qstate->region, qstate->env, ve,
|
||||
dnskey_rrset, ta->ds_rrset, ta->dnskey_rrset, downprot,
|
||||
&reason, &reason_bogus, qstate, reasonbuf, sizeof(reasonbuf));
|
||||
&reason, &reason_bogus, qstate, vq, reasonbuf,
|
||||
sizeof(reasonbuf));
|
||||
if(!kkey) {
|
||||
log_err("out of memory: verifying prime TA");
|
||||
return NULL;
|
||||
@@ -3040,7 +3070,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
* bogus, then we are done. */
|
||||
sec = val_verify_rrset_entry(qstate->env, ve, ds,
|
||||
vq->key_entry, &reason, &reason_bogus,
|
||||
LDNS_SECTION_ANSWER, qstate, &verified, reasonbuf,
|
||||
LDNS_SECTION_ANSWER, qstate, vq, &verified, reasonbuf,
|
||||
sizeof(reasonbuf));
|
||||
if(sec != sec_status_secure) {
|
||||
verbose(VERB_DETAIL, "DS rrset in DS response did "
|
||||
@@ -3091,7 +3121,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
/* Try to prove absence of the DS with NSEC */
|
||||
sec = val_nsec_prove_nodata_dsreply(
|
||||
qstate->env, ve, qinfo, msg->rep, vq->key_entry,
|
||||
&proof_ttl, &reason, &reason_bogus, qstate,
|
||||
&proof_ttl, &reason, &reason_bogus, qstate, vq,
|
||||
reasonbuf, sizeof(reasonbuf));
|
||||
switch(sec) {
|
||||
case sec_status_secure:
|
||||
@@ -3129,7 +3159,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
sec = nsec3_prove_nods(qstate->env, ve,
|
||||
msg->rep->rrsets + msg->rep->an_numrrsets,
|
||||
msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason,
|
||||
&reason_bogus, qstate, &vq->nsec3_cache_table,
|
||||
&reason_bogus, qstate, vq, &vq->nsec3_cache_table,
|
||||
reasonbuf, sizeof(reasonbuf));
|
||||
switch(sec) {
|
||||
case sec_status_insecure:
|
||||
@@ -3197,7 +3227,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
}
|
||||
sec = val_verify_rrset_entry(qstate->env, ve, cname,
|
||||
vq->key_entry, &reason, &reason_bogus,
|
||||
LDNS_SECTION_ANSWER, qstate, &verified, reasonbuf,
|
||||
LDNS_SECTION_ANSWER, qstate, vq, &verified, reasonbuf,
|
||||
sizeof(reasonbuf));
|
||||
if(sec == sec_status_secure) {
|
||||
/* Check for wildcard expansion */
|
||||
@@ -3318,6 +3348,7 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
uint8_t* olds = vq->empty_DS_name;
|
||||
int ret;
|
||||
*suspend = 0;
|
||||
vq->num_nsec_attempts = 0;
|
||||
vq->empty_DS_name = NULL;
|
||||
if(sub_qstate && sub_qstate->rpz_applied) {
|
||||
verbose(VERB_ALGO, "rpz was applied to the DS lookup, "
|
||||
@@ -3329,6 +3360,8 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
}
|
||||
ret = ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske,
|
||||
sub_qstate);
|
||||
/* New NSEC attempt count for next message validation. */
|
||||
vq->num_nsec_attempts = 0;
|
||||
if(ret != 0) {
|
||||
switch(ret) {
|
||||
case 1:
|
||||
@@ -3370,7 +3403,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 < ve->max_restart) {
|
||||
&& val_can_restart(qstate, vq, ve)) {
|
||||
vq->empty_DS_name = olds;
|
||||
val_blacklist(&vq->chain_blacklist, qstate->region, origin, 1);
|
||||
qstate->errinf = NULL;
|
||||
@@ -3420,6 +3453,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
char* reason = NULL;
|
||||
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
|
||||
vq->num_nsec_attempts = 0;
|
||||
if(sub_qstate && sub_qstate->rpz_applied) {
|
||||
verbose(VERB_ALGO, "rpz was applied to the DNSKEY lookup, "
|
||||
"make it insecure");
|
||||
@@ -3439,7 +3473,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to "
|
||||
"DNSKEY query.");
|
||||
|
||||
if(vq->restart_count < ve->max_restart) {
|
||||
if(val_can_restart(qstate, vq, ve)) {
|
||||
val_blacklist(&vq->chain_blacklist, qstate->region,
|
||||
origin, 1);
|
||||
qstate->errinf = NULL;
|
||||
@@ -3476,7 +3510,9 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
downprot = qstate->env->cfg->harden_algo_downgrade;
|
||||
vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env,
|
||||
ve, dnskey, vq->ds_rrset, downprot, &reason, &reason_bogus,
|
||||
qstate, reasonbuf, sizeof(reasonbuf));
|
||||
qstate, vq, reasonbuf, sizeof(reasonbuf));
|
||||
/* New NSEC attempt count for next message validation. */
|
||||
vq->num_nsec_attempts = 0;
|
||||
|
||||
if(!vq->key_entry) {
|
||||
log_err("out of memory in verify new DNSKEYs");
|
||||
@@ -3487,7 +3523,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 < ve->max_restart) {
|
||||
if(val_can_restart(qstate, vq, ve)) {
|
||||
val_blacklist(&vq->chain_blacklist,
|
||||
qstate->region, origin, 1);
|
||||
qstate->errinf = NULL;
|
||||
@@ -3539,6 +3575,7 @@ process_prime_response(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
struct trust_anchor* ta = anchor_find(qstate->env->anchors,
|
||||
vq->trust_anchor_name, vq->trust_anchor_labs,
|
||||
vq->trust_anchor_len, vq->qchase.qclass);
|
||||
vq->num_nsec_attempts = 0;
|
||||
if(!ta) {
|
||||
/* trust anchor revoked, restart with less anchors */
|
||||
vq->state = VAL_INIT_STATE;
|
||||
@@ -3557,19 +3594,23 @@ process_prime_response(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
|
||||
if(ta->autr) {
|
||||
if(!autr_process_prime(qstate->env, ve, ta, dnskey_rrset,
|
||||
qstate)) {
|
||||
qstate, vq)) {
|
||||
/* New NSEC attempt count for next message validation. */
|
||||
vq->num_nsec_attempts = 0;
|
||||
/* trust anchor revoked, restart with less anchors */
|
||||
vq->state = VAL_INIT_STATE;
|
||||
vq->trust_anchor_name = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, id,
|
||||
vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, vq, id,
|
||||
sub_qstate);
|
||||
lock_basic_unlock(&ta->lock);
|
||||
/* New NSEC attempt count for next message validation. */
|
||||
vq->num_nsec_attempts = 0;
|
||||
if(vq->key_entry) {
|
||||
if(key_entry_isbad(vq->key_entry)
|
||||
&& vq->restart_count < ve->max_restart) {
|
||||
&& val_can_restart(qstate, vq, ve)) {
|
||||
val_blacklist(&vq->chain_blacklist, qstate->region,
|
||||
origin, 1);
|
||||
qstate->errinf = NULL;
|
||||
|
||||
@@ -231,6 +231,19 @@ struct val_qstate {
|
||||
struct comm_timer* suspend_timer;
|
||||
/** Number of suspends */
|
||||
int suspend_count;
|
||||
|
||||
/** Number of DNSKEY RRSIG validation attempts. This is the number of
|
||||
* cryptographic operations done for the mesh state. */
|
||||
int num_validation_attempts;
|
||||
/** Number of DS hash verification attempts. This is the number of
|
||||
* hash operations done for the mesh state.
|
||||
* It does not count NSEC3 hashes. */
|
||||
int num_hash_attempts;
|
||||
/** Number of NSEC validations. And NSEC3 too. This is reset per
|
||||
* answer. */
|
||||
int num_nsec_attempts;
|
||||
/** The nsec attempts have been exceeded. */
|
||||
int num_nsec_attempts_exceeded;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user