sync with OpenBSD -current
This commit is contained in:
parent
c151d49b7a
commit
be76e7e421
|
@ -1,4 +1,4 @@
|
|||
.\" $OpenBSD: d2i_ASN1_OCTET_STRING.3,v 1.19 2022/09/12 14:36:09 tb Exp $
|
||||
.\" $OpenBSD: d2i_ASN1_OCTET_STRING.3,v 1.20 2024/02/13 12:38:43 job Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
.\"
|
||||
|
@ -14,7 +14,7 @@
|
|||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: September 12 2022 $
|
||||
.Dd $Mdocdate: February 13 2024 $
|
||||
.Dt D2I_ASN1_OCTET_STRING 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -452,3 +452,10 @@ and
|
|||
.Fn i2d_ASN1_GENERALSTRING
|
||||
first appeared in OpenSSL 0.9.7 and have been available since
|
||||
.Ox 3.2 .
|
||||
.Sh CAVEATS
|
||||
Other implementations may accept or emit invalid DER encodings of
|
||||
GeneralizedTime and UTCTime.
|
||||
Portable applications should use
|
||||
.Fn ASN1_STRING_length
|
||||
to double check whether a given GeneralizedTime or UTCTime object is at least
|
||||
15 or 13 bytes, respectively.
|
||||
|
|
|
@ -509,12 +509,12 @@ typedef uLong FAR uLongf;
|
|||
|
||||
#if !defined(_WIN32) && defined(Z_LARGE64)
|
||||
# define z_off64_t off64_t
|
||||
#elif defined(_WIN32) && !defined(__GNUC__)
|
||||
# define z_off64_t __int64
|
||||
#elif defined(__GO32__)
|
||||
# define z_off64_t offset_t
|
||||
#else
|
||||
# if defined(_WIN32) && !defined(__GNUC__)
|
||||
# define z_off64_t __int64
|
||||
# else
|
||||
# define z_off64_t z_off_t
|
||||
# endif
|
||||
# define z_off64_t z_off_t
|
||||
#endif
|
||||
|
||||
/* MVS linker does not support external names larger than 8 bytes */
|
||||
|
|
|
@ -1891,9 +1891,9 @@ ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */
|
|||
ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int);
|
||||
ZEXTERN z_off_t ZEXPORT gztell64(gzFile);
|
||||
ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile);
|
||||
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);
|
||||
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t);
|
||||
# endif
|
||||
#else
|
||||
ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *);
|
||||
|
|
|
@ -170,11 +170,10 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
|
|||
#endif
|
||||
|
||||
/* provide prototypes for these when building zlib without LFS */
|
||||
#if !defined(_WIN32) && \
|
||||
(!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
|
||||
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);
|
||||
#ifndef Z_LARGE64
|
||||
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t);
|
||||
#endif
|
||||
|
||||
/* common defaults */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: engine.c,v 1.42 2024/01/26 21:14:08 jan Exp $ */
|
||||
/* $OpenBSD: engine.c,v 1.43 2024/02/13 12:53:05 florian Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org>
|
||||
|
@ -1385,8 +1385,6 @@ state_transition(struct dhcpleased_iface *iface, enum if_state new_state)
|
|||
char ifnamebuf[IF_NAMESIZE], *if_name;
|
||||
|
||||
iface->state = new_state;
|
||||
if (new_state != old_state)
|
||||
iface->xid = arc4random();
|
||||
|
||||
switch (new_state) {
|
||||
case IF_DOWN:
|
||||
|
@ -1426,6 +1424,7 @@ state_transition(struct dhcpleased_iface *iface, enum if_state new_state)
|
|||
case IF_DOWN:
|
||||
case IF_IPV6_ONLY:
|
||||
iface->timo.tv_sec = START_EXP_BACKOFF;
|
||||
iface->xid = arc4random();
|
||||
break;
|
||||
case IF_BOUND:
|
||||
fatal("invalid transition Bound -> Init");
|
||||
|
@ -1436,8 +1435,10 @@ state_transition(struct dhcpleased_iface *iface, enum if_state new_state)
|
|||
case IF_REBOOTING:
|
||||
if (old_state == IF_REBOOTING)
|
||||
iface->timo.tv_sec *= 2;
|
||||
else
|
||||
else {
|
||||
iface->timo.tv_sec = START_EXP_BACKOFF;
|
||||
iface->xid = arc4random();
|
||||
}
|
||||
request_dhcp_request(iface);
|
||||
break;
|
||||
case IF_REQUESTING:
|
||||
|
@ -1458,6 +1459,7 @@ state_transition(struct dhcpleased_iface *iface, enum if_state new_state)
|
|||
if (old_state == IF_BOUND) {
|
||||
iface->timo.tv_sec = (iface->rebinding_time -
|
||||
iface->renewal_time) / 2; /* RFC 2131 4.4.5 */
|
||||
iface->xid = arc4random();
|
||||
} else
|
||||
iface->timo.tv_sec /= 2;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ca.c,v 1.100 2024/02/06 13:10:56 tobhe Exp $ */
|
||||
/* $OpenBSD: ca.c,v 1.101 2024/02/13 12:25:11 tobhe Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
|
||||
|
@ -332,6 +332,14 @@ ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
|
|||
unsigned int mode;
|
||||
|
||||
switch (imsg->hdr.type) {
|
||||
case IMSG_CTL_ACTIVE:
|
||||
case IMSG_CTL_PASSIVE:
|
||||
/*
|
||||
* send back to indicate we have processed
|
||||
* all messages from parent.
|
||||
*/
|
||||
proc_compose(&env->sc_ps, PROC_PARENT, imsg->hdr.type, NULL, 0);
|
||||
break;
|
||||
case IMSG_CTL_RESET:
|
||||
IMSG_SIZE_CHECK(imsg, &mode);
|
||||
memcpy(&mode, imsg->data, sizeof(mode));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: config.c,v 1.95 2024/01/17 08:25:02 claudio Exp $ */
|
||||
/* $OpenBSD: config.c,v 1.96 2024/02/13 12:25:11 tobhe Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
|
||||
|
@ -507,8 +507,14 @@ config_setmode(struct iked *env, unsigned int passive)
|
|||
{
|
||||
unsigned int type;
|
||||
|
||||
/*
|
||||
* In order to control the startup of the processes,
|
||||
* the messages are sent in this order:
|
||||
* PROC_PARENT -> PROC_CERT -> PROC_PARENT -> PROC_IKEV2
|
||||
* so PROC_CERT is ready before PROC_IKEV2 is activated.
|
||||
*/
|
||||
type = passive ? IMSG_CTL_PASSIVE : IMSG_CTL_ACTIVE;
|
||||
proc_compose(&env->sc_ps, PROC_IKEV2, type, NULL, 0);
|
||||
proc_compose(&env->sc_ps, PROC_CERT, type, NULL, 0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: iked.c,v 1.67 2024/01/15 15:29:00 tobhe Exp $ */
|
||||
/* $OpenBSD: iked.c,v 1.68 2024/02/13 12:25:11 tobhe Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
|
||||
|
@ -422,6 +422,10 @@ parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg)
|
|||
struct iked *env = iked_env;
|
||||
|
||||
switch (imsg->hdr.type) {
|
||||
case IMSG_CTL_ACTIVE:
|
||||
case IMSG_CTL_PASSIVE:
|
||||
proc_forward_imsg(&env->sc_ps, imsg, PROC_IKEV2, -1);
|
||||
break;
|
||||
case IMSG_OCSP_FD:
|
||||
ocsp_connect(env, imsg);
|
||||
break;
|
||||
|
|
|
@ -7771,6 +7771,7 @@ static int zonemd_dnssec_verify_rrset(struct auth_zone* z,
|
|||
enum sec_status sec;
|
||||
struct val_env* ve;
|
||||
int m;
|
||||
int verified = 0;
|
||||
m = modstack_find(mods, "validator");
|
||||
if(m == -1) {
|
||||
auth_zone_log(z->name, VERB_ALGO, "zonemd dnssec verify: have "
|
||||
|
@ -7794,7 +7795,7 @@ 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);
|
||||
LDNS_SECTION_ANSWER, NULL, &verified);
|
||||
if(sec == sec_status_secure) {
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -690,6 +690,28 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
|
|||
return msg;
|
||||
}
|
||||
|
||||
struct dns_msg*
|
||||
dns_msg_deepcopy_region(struct dns_msg* origin, struct regional* region)
|
||||
{
|
||||
size_t i;
|
||||
struct dns_msg* res = NULL;
|
||||
res = gen_dns_msg(region, &origin->qinfo, origin->rep->rrset_count);
|
||||
if(!res) return NULL;
|
||||
*res->rep = *origin->rep;
|
||||
if(origin->rep->reason_bogus_str) {
|
||||
res->rep->reason_bogus_str = regional_strdup(region,
|
||||
origin->rep->reason_bogus_str);
|
||||
}
|
||||
for(i=0; i<res->rep->rrset_count; i++) {
|
||||
res->rep->rrsets[i] = packed_rrset_copy_region(
|
||||
origin->rep->rrsets[i], region, 0);
|
||||
if(!res->rep->rrsets[i]) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/** synthesize RRset-only response from cached RRset item */
|
||||
static struct dns_msg*
|
||||
rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
|
|
|
@ -164,6 +164,15 @@ struct dns_msg* tomsg(struct module_env* env, struct query_info* q,
|
|||
struct reply_info* r, struct regional* region, time_t now,
|
||||
int allow_expired, struct regional* scratch);
|
||||
|
||||
/**
|
||||
* Deep copy a dns_msg to a region.
|
||||
* @param origin: the dns_msg to copy.
|
||||
* @param region: the region to copy all the data to.
|
||||
* @return the new dns_msg or NULL on malloc error.
|
||||
*/
|
||||
struct dns_msg* dns_msg_deepcopy_region(struct dns_msg* origin,
|
||||
struct regional* region);
|
||||
|
||||
/**
|
||||
* Find cached message
|
||||
* @param env: module environment with the DNS cache.
|
||||
|
|
|
@ -131,6 +131,7 @@ fptr_whitelist_comm_timer(void (*fptr)(void*))
|
|||
else if(fptr == &pending_udp_timer_delay_cb) return 1;
|
||||
else if(fptr == &worker_stat_timer_cb) return 1;
|
||||
else if(fptr == &worker_probe_timer_cb) return 1;
|
||||
else if(fptr == &validate_suspend_timer_cb) return 1;
|
||||
#ifdef UB_ON_WINDOWS
|
||||
else if(fptr == &wsvc_cron_cb) return 1;
|
||||
#endif
|
||||
|
|
|
@ -181,6 +181,7 @@ nsec_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
{
|
||||
struct packed_rrset_data* d = (struct packed_rrset_data*)
|
||||
nsec->entry.data;
|
||||
int verified = 0;
|
||||
if(!d) return 0;
|
||||
if(d->security == sec_status_secure)
|
||||
return 1;
|
||||
|
@ -188,7 +189,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);
|
||||
reason_bogus, LDNS_SECTION_AUTHORITY, qstate, &verified);
|
||||
if(d->security == sec_status_secure) {
|
||||
rrset_update_sec_status(env->rrset_cache, nsec, *env->now);
|
||||
return 1;
|
||||
|
|
|
@ -57,6 +57,19 @@
|
|||
/* we include nsec.h for the bitmap_has_type function */
|
||||
#include "validator/val_nsec.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
#include "util/config_file.h"
|
||||
|
||||
/**
|
||||
* Max number of NSEC3 calculations at once, suspend query for later.
|
||||
* 8 is low enough and allows for cases where multiple proofs are needed.
|
||||
*/
|
||||
#define MAX_NSEC3_CALCULATIONS 8
|
||||
/**
|
||||
* When all allowed NSEC3 calculations at once resulted in error treat as
|
||||
* bogus. NSEC3 hash errors are not cached and this helps breaks loops with
|
||||
* erroneous data.
|
||||
*/
|
||||
#define MAX_NSEC3_ERRORS -1
|
||||
|
||||
/**
|
||||
* This function we get from ldns-compat or from base system
|
||||
|
@ -532,6 +545,17 @@ nsec3_hash_cmp(const void* c1, const void* c2)
|
|||
return memcmp(s1, s2, s1len);
|
||||
}
|
||||
|
||||
int
|
||||
nsec3_cache_table_init(struct nsec3_cache_table* ct, struct regional* region)
|
||||
{
|
||||
if(ct->ct) return 1;
|
||||
ct->ct = (rbtree_type*)regional_alloc(region, sizeof(*ct->ct));
|
||||
if(!ct->ct) return 0;
|
||||
ct->region = region;
|
||||
rbtree_init(ct->ct, &nsec3_hash_cmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t
|
||||
nsec3_get_hashed(sldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo,
|
||||
size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res, size_t max)
|
||||
|
@ -646,7 +670,7 @@ nsec3_hash_name(rbtree_type* table, struct regional* region, sldns_buffer* buf,
|
|||
c = (struct nsec3_cached_hash*)rbtree_search(table, &looki);
|
||||
if(c) {
|
||||
*hash = c;
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
/* create a new entry */
|
||||
c = (struct nsec3_cached_hash*)regional_alloc(region, sizeof(*c));
|
||||
|
@ -658,10 +682,10 @@ nsec3_hash_name(rbtree_type* table, struct regional* region, sldns_buffer* buf,
|
|||
c->dname_len = dname_len;
|
||||
r = nsec3_calc_hash(region, buf, c);
|
||||
if(r != 1)
|
||||
return r;
|
||||
return r; /* returns -1 or 0 */
|
||||
r = nsec3_calc_b32(region, buf, c);
|
||||
if(r != 1)
|
||||
return r;
|
||||
return r; /* returns 0 */
|
||||
#ifdef UNBOUND_DEBUG
|
||||
n =
|
||||
#else
|
||||
|
@ -704,6 +728,7 @@ nsec3_hash_matches_owner(struct nsec3_filter* flt,
|
|||
struct nsec3_cached_hash* hash, struct ub_packed_rrset_key* s)
|
||||
{
|
||||
uint8_t* nm = s->rk.dname;
|
||||
if(!hash) return 0; /* please clang */
|
||||
/* compare, does hash of name based on params in this NSEC3
|
||||
* match the owner name of this NSEC3?
|
||||
* name must be: <hashlength>base32 . zone name
|
||||
|
@ -730,34 +755,50 @@ nsec3_hash_matches_owner(struct nsec3_filter* flt,
|
|||
* @param nmlen: length of name.
|
||||
* @param rrset: nsec3 that matches is returned here.
|
||||
* @param rr: rr number in nsec3 rrset that matches.
|
||||
* @param calculations: current hash calculations.
|
||||
* @return true if a matching NSEC3 is found, false if not.
|
||||
*/
|
||||
static int
|
||||
find_matching_nsec3(struct module_env* env, struct nsec3_filter* flt,
|
||||
rbtree_type* ct, uint8_t* nm, size_t nmlen,
|
||||
struct ub_packed_rrset_key** rrset, int* rr)
|
||||
struct nsec3_cache_table* ct, uint8_t* nm, size_t nmlen,
|
||||
struct ub_packed_rrset_key** rrset, int* rr,
|
||||
int* calculations)
|
||||
{
|
||||
size_t i_rs;
|
||||
int i_rr;
|
||||
struct ub_packed_rrset_key* s;
|
||||
struct nsec3_cached_hash* hash = NULL;
|
||||
int r;
|
||||
int calc_errors = 0;
|
||||
|
||||
/* this loop skips other-zone and unknown NSEC3s, also non-NSEC3 RRs */
|
||||
for(s=filter_first(flt, &i_rs, &i_rr); s;
|
||||
s=filter_next(flt, &i_rs, &i_rr)) {
|
||||
/* check if we are allowed more calculations */
|
||||
if(*calculations >= MAX_NSEC3_CALCULATIONS) {
|
||||
if(calc_errors == *calculations) {
|
||||
*calculations = MAX_NSEC3_ERRORS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* get name hashed for this NSEC3 RR */
|
||||
r = nsec3_hash_name(ct, env->scratch, env->scratch_buffer,
|
||||
r = nsec3_hash_name(ct->ct, ct->region, env->scratch_buffer,
|
||||
s, i_rr, nm, nmlen, &hash);
|
||||
if(r == 0) {
|
||||
log_err("nsec3: malloc failure");
|
||||
break; /* alloc failure */
|
||||
} else if(r != 1)
|
||||
continue; /* malformed NSEC3 */
|
||||
else if(nsec3_hash_matches_owner(flt, hash, s)) {
|
||||
*rrset = s; /* rrset with this name */
|
||||
*rr = i_rr; /* matches hash with these parameters */
|
||||
return 1;
|
||||
} else if(r < 0) {
|
||||
/* malformed NSEC3 */
|
||||
calc_errors++;
|
||||
(*calculations)++;
|
||||
continue;
|
||||
} else {
|
||||
if(r == 1) (*calculations)++;
|
||||
if(nsec3_hash_matches_owner(flt, hash, s)) {
|
||||
*rrset = s; /* rrset with this name */
|
||||
*rr = i_rr; /* matches hash with these parameters */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
*rrset = NULL;
|
||||
|
@ -775,6 +816,7 @@ nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash,
|
|||
if(!nsec3_get_nextowner(rrset, rr, &next, &nextlen))
|
||||
return 0; /* malformed RR proves nothing */
|
||||
|
||||
if(!hash) return 0; /* please clang */
|
||||
/* check the owner name is a hashed value . apex
|
||||
* base32 encoded values must have equal length.
|
||||
* hash_value and next hash value must have equal length. */
|
||||
|
@ -823,35 +865,51 @@ nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash,
|
|||
* @param nmlen: length of name.
|
||||
* @param rrset: covering NSEC3 rrset is returned here.
|
||||
* @param rr: rr of cover is returned here.
|
||||
* @param calculations: current hash calculations.
|
||||
* @return true if a covering NSEC3 is found, false if not.
|
||||
*/
|
||||
static int
|
||||
find_covering_nsec3(struct module_env* env, struct nsec3_filter* flt,
|
||||
rbtree_type* ct, uint8_t* nm, size_t nmlen,
|
||||
struct ub_packed_rrset_key** rrset, int* rr)
|
||||
struct nsec3_cache_table* ct, uint8_t* nm, size_t nmlen,
|
||||
struct ub_packed_rrset_key** rrset, int* rr,
|
||||
int* calculations)
|
||||
{
|
||||
size_t i_rs;
|
||||
int i_rr;
|
||||
struct ub_packed_rrset_key* s;
|
||||
struct nsec3_cached_hash* hash = NULL;
|
||||
int r;
|
||||
int calc_errors = 0;
|
||||
|
||||
/* this loop skips other-zone and unknown NSEC3s, also non-NSEC3 RRs */
|
||||
for(s=filter_first(flt, &i_rs, &i_rr); s;
|
||||
s=filter_next(flt, &i_rs, &i_rr)) {
|
||||
/* check if we are allowed more calculations */
|
||||
if(*calculations >= MAX_NSEC3_CALCULATIONS) {
|
||||
if(calc_errors == *calculations) {
|
||||
*calculations = MAX_NSEC3_ERRORS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* get name hashed for this NSEC3 RR */
|
||||
r = nsec3_hash_name(ct, env->scratch, env->scratch_buffer,
|
||||
r = nsec3_hash_name(ct->ct, ct->region, env->scratch_buffer,
|
||||
s, i_rr, nm, nmlen, &hash);
|
||||
if(r == 0) {
|
||||
log_err("nsec3: malloc failure");
|
||||
break; /* alloc failure */
|
||||
} else if(r != 1)
|
||||
continue; /* malformed NSEC3 */
|
||||
else if(nsec3_covers(flt->zone, hash, s, i_rr,
|
||||
env->scratch_buffer)) {
|
||||
*rrset = s; /* rrset with this name */
|
||||
*rr = i_rr; /* covers hash with these parameters */
|
||||
return 1;
|
||||
} else if(r < 0) {
|
||||
/* malformed NSEC3 */
|
||||
calc_errors++;
|
||||
(*calculations)++;
|
||||
continue;
|
||||
} else {
|
||||
if(r == 1) (*calculations)++;
|
||||
if(nsec3_covers(flt->zone, hash, s, i_rr,
|
||||
env->scratch_buffer)) {
|
||||
*rrset = s; /* rrset with this name */
|
||||
*rr = i_rr; /* covers hash with these parameters */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
*rrset = NULL;
|
||||
|
@ -869,11 +927,13 @@ find_covering_nsec3(struct module_env* env, struct nsec3_filter* flt,
|
|||
* @param ct: cached hashes table.
|
||||
* @param qinfo: query that is verified for.
|
||||
* @param ce: closest encloser information is returned in here.
|
||||
* @param calculations: current hash calculations.
|
||||
* @return true if a closest encloser candidate is found, false if not.
|
||||
*/
|
||||
static int
|
||||
nsec3_find_closest_encloser(struct module_env* env, struct nsec3_filter* flt,
|
||||
rbtree_type* ct, struct query_info* qinfo, struct ce_response* ce)
|
||||
struct nsec3_cache_table* ct, struct query_info* qinfo,
|
||||
struct ce_response* ce, int* calculations)
|
||||
{
|
||||
uint8_t* nm = qinfo->qname;
|
||||
size_t nmlen = qinfo->qname_len;
|
||||
|
@ -888,8 +948,12 @@ nsec3_find_closest_encloser(struct module_env* env, struct nsec3_filter* flt,
|
|||
* may be the case. */
|
||||
|
||||
while(dname_subdomain_c(nm, flt->zone)) {
|
||||
if(*calculations >= MAX_NSEC3_CALCULATIONS ||
|
||||
*calculations == MAX_NSEC3_ERRORS) {
|
||||
return 0;
|
||||
}
|
||||
if(find_matching_nsec3(env, flt, ct, nm, nmlen,
|
||||
&ce->ce_rrset, &ce->ce_rr)) {
|
||||
&ce->ce_rrset, &ce->ce_rr, calculations)) {
|
||||
ce->ce = nm;
|
||||
ce->ce_len = nmlen;
|
||||
return 1;
|
||||
|
@ -933,22 +997,38 @@ next_closer(uint8_t* qname, size_t qnamelen, uint8_t* ce,
|
|||
* If set true, and the return value is true, then you can be
|
||||
* certain that the ce.nc_rrset and ce.nc_rr are set properly.
|
||||
* @param ce: closest encloser information is returned in here.
|
||||
* @param calculations: pointer to the current NSEC3 hash calculations.
|
||||
* @return bogus if no closest encloser could be proven.
|
||||
* secure if a closest encloser could be proven, ce is set.
|
||||
* insecure if the closest-encloser candidate turns out to prove
|
||||
* that an insecure delegation exists above the qname.
|
||||
* unchecked if no more hash calculations are allowed at this point.
|
||||
*/
|
||||
static enum sec_status
|
||||
nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt,
|
||||
rbtree_type* ct, struct query_info* qinfo, int prove_does_not_exist,
|
||||
struct ce_response* ce)
|
||||
struct nsec3_cache_table* ct, struct query_info* qinfo,
|
||||
int prove_does_not_exist, struct ce_response* ce, int* calculations)
|
||||
{
|
||||
uint8_t* nc;
|
||||
size_t nc_len;
|
||||
/* robust: clean out ce, in case it gets abused later */
|
||||
memset(ce, 0, sizeof(*ce));
|
||||
|
||||
if(!nsec3_find_closest_encloser(env, flt, ct, qinfo, ce)) {
|
||||
if(!nsec3_find_closest_encloser(env, flt, ct, qinfo, ce, calculations)) {
|
||||
if(*calculations == MAX_NSEC3_ERRORS) {
|
||||
verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could "
|
||||
"not find a candidate for the closest "
|
||||
"encloser; all attempted hash calculations "
|
||||
"were erroneous; bogus");
|
||||
return sec_status_bogus;
|
||||
} else if(*calculations >= MAX_NSEC3_CALCULATIONS) {
|
||||
verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could "
|
||||
"not find a candidate for the closest "
|
||||
"encloser; reached MAX_NSEC3_CALCULATIONS "
|
||||
"(%d); unchecked still",
|
||||
MAX_NSEC3_CALCULATIONS);
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could "
|
||||
"not find a candidate for the closest encloser.");
|
||||
return sec_status_bogus;
|
||||
|
@ -989,9 +1069,23 @@ nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt,
|
|||
/* Otherwise, we need to show that the next closer name is covered. */
|
||||
next_closer(qinfo->qname, qinfo->qname_len, ce->ce, &nc, &nc_len);
|
||||
if(!find_covering_nsec3(env, flt, ct, nc, nc_len,
|
||||
&ce->nc_rrset, &ce->nc_rr)) {
|
||||
&ce->nc_rrset, &ce->nc_rr, calculations)) {
|
||||
if(*calculations == MAX_NSEC3_ERRORS) {
|
||||
verbose(VERB_ALGO, "nsec3: Could not find proof that the "
|
||||
"candidate encloser was the closest encloser; "
|
||||
"all attempted hash calculations were "
|
||||
"erroneous; bogus");
|
||||
return sec_status_bogus;
|
||||
} else if(*calculations >= MAX_NSEC3_CALCULATIONS) {
|
||||
verbose(VERB_ALGO, "nsec3: Could not find proof that the "
|
||||
"candidate encloser was the closest encloser; "
|
||||
"reached MAX_NSEC3_CALCULATIONS (%d); "
|
||||
"unchecked still",
|
||||
MAX_NSEC3_CALCULATIONS);
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
verbose(VERB_ALGO, "nsec3: Could not find proof that the "
|
||||
"candidate encloser was the closest encloser");
|
||||
"candidate encloser was the closest encloser");
|
||||
return sec_status_bogus;
|
||||
}
|
||||
return sec_status_secure;
|
||||
|
@ -1020,7 +1114,7 @@ nsec3_ce_wildcard(struct regional* region, uint8_t* ce, size_t celen,
|
|||
/** Do the name error proof */
|
||||
static enum sec_status
|
||||
nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt,
|
||||
rbtree_type* ct, struct query_info* qinfo)
|
||||
struct nsec3_cache_table* ct, struct query_info* qinfo, int* calc)
|
||||
{
|
||||
struct ce_response ce;
|
||||
uint8_t* wc;
|
||||
|
@ -1032,11 +1126,15 @@ nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt,
|
|||
/* First locate and prove the closest encloser to qname. We will
|
||||
* use the variant that fails if the closest encloser turns out
|
||||
* to be qname. */
|
||||
sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce);
|
||||
sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce, calc);
|
||||
if(sec != sec_status_secure) {
|
||||
if(sec == sec_status_bogus)
|
||||
verbose(VERB_ALGO, "nsec3 nameerror proof: failed "
|
||||
"to prove a closest encloser");
|
||||
else if(sec == sec_status_unchecked)
|
||||
verbose(VERB_ALGO, "nsec3 nameerror proof: will "
|
||||
"continue proving closest encloser after "
|
||||
"suspend");
|
||||
else verbose(VERB_ALGO, "nsec3 nameerror proof: closest "
|
||||
"nsec3 is an insecure delegation");
|
||||
return sec;
|
||||
|
@ -1046,9 +1144,27 @@ nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt,
|
|||
/* At this point, we know that qname does not exist. Now we need
|
||||
* to prove that the wildcard does not exist. */
|
||||
log_assert(ce.ce);
|
||||
wc = nsec3_ce_wildcard(env->scratch, ce.ce, ce.ce_len, &wclen);
|
||||
if(!wc || !find_covering_nsec3(env, flt, ct, wc, wclen,
|
||||
&wc_rrset, &wc_rr)) {
|
||||
wc = nsec3_ce_wildcard(ct->region, ce.ce, ce.ce_len, &wclen);
|
||||
if(!wc) {
|
||||
verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove "
|
||||
"that the applicable wildcard did not exist.");
|
||||
return sec_status_bogus;
|
||||
}
|
||||
if(!find_covering_nsec3(env, flt, ct, wc, wclen, &wc_rrset, &wc_rr, calc)) {
|
||||
if(*calc == MAX_NSEC3_ERRORS) {
|
||||
verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove "
|
||||
"that the applicable wildcard did not exist; "
|
||||
"all attempted hash calculations were "
|
||||
"erroneous; bogus");
|
||||
return sec_status_bogus;
|
||||
} else if(*calc >= MAX_NSEC3_CALCULATIONS) {
|
||||
verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove "
|
||||
"that the applicable wildcard did not exist; "
|
||||
"reached MAX_NSEC3_CALCULATIONS (%d); "
|
||||
"unchecked still",
|
||||
MAX_NSEC3_CALCULATIONS);
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove "
|
||||
"that the applicable wildcard did not exist.");
|
||||
return sec_status_bogus;
|
||||
|
@ -1064,14 +1180,13 @@ nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt,
|
|||
enum sec_status
|
||||
nsec3_prove_nameerror(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)
|
||||
struct query_info* qinfo, struct key_entry_key* kkey,
|
||||
struct nsec3_cache_table* ct, int* calc)
|
||||
{
|
||||
rbtree_type ct;
|
||||
struct nsec3_filter flt;
|
||||
|
||||
if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
|
||||
return sec_status_bogus; /* no valid NSEC3s, bogus */
|
||||
rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
|
||||
filter_init(&flt, list, num, qinfo); /* init RR iterator */
|
||||
if(!flt.zone)
|
||||
return sec_status_bogus; /* no RRs */
|
||||
|
@ -1079,7 +1194,7 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve,
|
|||
return sec_status_insecure; /* iteration count too high */
|
||||
log_nametypeclass(VERB_ALGO, "start nsec3 nameerror proof, zone",
|
||||
flt.zone, 0, 0);
|
||||
return nsec3_do_prove_nameerror(env, &flt, &ct, qinfo);
|
||||
return nsec3_do_prove_nameerror(env, &flt, ct, qinfo, calc);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1090,7 +1205,8 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve,
|
|||
/** Do the nodata proof */
|
||||
static enum sec_status
|
||||
nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt,
|
||||
rbtree_type* ct, struct query_info* qinfo)
|
||||
struct nsec3_cache_table* ct, struct query_info* qinfo,
|
||||
int* calc)
|
||||
{
|
||||
struct ce_response ce;
|
||||
uint8_t* wc;
|
||||
|
@ -1100,7 +1216,7 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt,
|
|||
enum sec_status sec;
|
||||
|
||||
if(find_matching_nsec3(env, flt, ct, qinfo->qname, qinfo->qname_len,
|
||||
&rrset, &rr)) {
|
||||
&rrset, &rr, calc)) {
|
||||
/* cases 1 and 2 */
|
||||
if(nsec3_has_type(rrset, rr, qinfo->qtype)) {
|
||||
verbose(VERB_ALGO, "proveNodata: Matching NSEC3 "
|
||||
|
@ -1144,11 +1260,23 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt,
|
|||
}
|
||||
return sec_status_secure;
|
||||
}
|
||||
if(*calc == MAX_NSEC3_ERRORS) {
|
||||
verbose(VERB_ALGO, "proveNodata: all attempted hash "
|
||||
"calculations were erroneous while finding a matching "
|
||||
"NSEC3, bogus");
|
||||
return sec_status_bogus;
|
||||
} else if(*calc >= MAX_NSEC3_CALCULATIONS) {
|
||||
verbose(VERB_ALGO, "proveNodata: reached "
|
||||
"MAX_NSEC3_CALCULATIONS (%d) while finding a "
|
||||
"matching NSEC3; unchecked still",
|
||||
MAX_NSEC3_CALCULATIONS);
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
|
||||
/* For cases 3 - 5, we need the proven closest encloser, and it
|
||||
* can't match qname. Although, at this point, we know that it
|
||||
* won't since we just checked that. */
|
||||
sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce);
|
||||
sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce, calc);
|
||||
if(sec == sec_status_bogus) {
|
||||
verbose(VERB_ALGO, "proveNodata: did not match qname, "
|
||||
"nor found a proven closest encloser.");
|
||||
|
@ -1157,14 +1285,17 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt,
|
|||
verbose(VERB_ALGO, "proveNodata: closest nsec3 is insecure "
|
||||
"delegation.");
|
||||
return sec_status_insecure;
|
||||
} else if(sec==sec_status_unchecked) {
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
|
||||
/* Case 3: removed */
|
||||
|
||||
/* Case 4: */
|
||||
log_assert(ce.ce);
|
||||
wc = nsec3_ce_wildcard(env->scratch, ce.ce, ce.ce_len, &wclen);
|
||||
if(wc && find_matching_nsec3(env, flt, ct, wc, wclen, &rrset, &rr)) {
|
||||
wc = nsec3_ce_wildcard(ct->region, ce.ce, ce.ce_len, &wclen);
|
||||
if(wc && find_matching_nsec3(env, flt, ct, wc, wclen, &rrset, &rr,
|
||||
calc)) {
|
||||
/* found wildcard */
|
||||
if(nsec3_has_type(rrset, rr, qinfo->qtype)) {
|
||||
verbose(VERB_ALGO, "nsec3 nodata proof: matching "
|
||||
|
@ -1195,6 +1326,18 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt,
|
|||
}
|
||||
return sec_status_secure;
|
||||
}
|
||||
if(*calc == MAX_NSEC3_ERRORS) {
|
||||
verbose(VERB_ALGO, "nsec3 nodata proof: all attempted hash "
|
||||
"calculations were erroneous while matching "
|
||||
"wildcard, bogus");
|
||||
return sec_status_bogus;
|
||||
} else if(*calc >= MAX_NSEC3_CALCULATIONS) {
|
||||
verbose(VERB_ALGO, "nsec3 nodata proof: reached "
|
||||
"MAX_NSEC3_CALCULATIONS (%d) while matching "
|
||||
"wildcard, unchecked still",
|
||||
MAX_NSEC3_CALCULATIONS);
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
|
||||
/* Case 5: */
|
||||
/* Due to forwarders, cnames, and other collating effects, we
|
||||
|
@ -1223,28 +1366,27 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt,
|
|||
enum sec_status
|
||||
nsec3_prove_nodata(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)
|
||||
struct query_info* qinfo, struct key_entry_key* kkey,
|
||||
struct nsec3_cache_table* ct, int* calc)
|
||||
{
|
||||
rbtree_type ct;
|
||||
struct nsec3_filter flt;
|
||||
|
||||
if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
|
||||
return sec_status_bogus; /* no valid NSEC3s, bogus */
|
||||
rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
|
||||
filter_init(&flt, list, num, qinfo); /* init RR iterator */
|
||||
if(!flt.zone)
|
||||
return sec_status_bogus; /* no RRs */
|
||||
if(nsec3_iteration_count_high(ve, &flt, kkey))
|
||||
return sec_status_insecure; /* iteration count too high */
|
||||
return nsec3_do_prove_nodata(env, &flt, &ct, qinfo);
|
||||
return nsec3_do_prove_nodata(env, &flt, ct, qinfo, calc);
|
||||
}
|
||||
|
||||
enum sec_status
|
||||
nsec3_prove_wildcard(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, uint8_t* wc)
|
||||
struct query_info* qinfo, struct key_entry_key* kkey, uint8_t* wc,
|
||||
struct nsec3_cache_table* ct, int* calc)
|
||||
{
|
||||
rbtree_type ct;
|
||||
struct nsec3_filter flt;
|
||||
struct ce_response ce;
|
||||
uint8_t* nc;
|
||||
|
@ -1254,7 +1396,6 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve,
|
|||
|
||||
if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
|
||||
return sec_status_bogus; /* no valid NSEC3s, bogus */
|
||||
rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
|
||||
filter_init(&flt, list, num, qinfo); /* init RR iterator */
|
||||
if(!flt.zone)
|
||||
return sec_status_bogus; /* no RRs */
|
||||
|
@ -1272,8 +1413,22 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve,
|
|||
/* Now we still need to prove that the original data did not exist.
|
||||
* Otherwise, we need to show that the next closer name is covered. */
|
||||
next_closer(qinfo->qname, qinfo->qname_len, ce.ce, &nc, &nc_len);
|
||||
if(!find_covering_nsec3(env, &flt, &ct, nc, nc_len,
|
||||
&ce.nc_rrset, &ce.nc_rr)) {
|
||||
if(!find_covering_nsec3(env, &flt, ct, nc, nc_len,
|
||||
&ce.nc_rrset, &ce.nc_rr, calc)) {
|
||||
if(*calc == MAX_NSEC3_ERRORS) {
|
||||
verbose(VERB_ALGO, "proveWildcard: did not find a "
|
||||
"covering NSEC3 that covered the next closer "
|
||||
"name; all attempted hash calculations were "
|
||||
"erroneous; bogus");
|
||||
return sec_status_bogus;
|
||||
} else if(*calc >= MAX_NSEC3_CALCULATIONS) {
|
||||
verbose(VERB_ALGO, "proveWildcard: did not find a "
|
||||
"covering NSEC3 that covered the next closer "
|
||||
"name; reached MAX_NSEC3_CALCULATIONS "
|
||||
"(%d); unchecked still",
|
||||
MAX_NSEC3_CALCULATIONS);
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
verbose(VERB_ALGO, "proveWildcard: did not find a covering "
|
||||
"NSEC3 that covered the next closer name.");
|
||||
return sec_status_bogus;
|
||||
|
@ -1294,6 +1449,7 @@ list_is_secure(struct module_env* env, struct val_env* ve,
|
|||
{
|
||||
struct packed_rrset_data* d;
|
||||
size_t i;
|
||||
int verified = 0;
|
||||
for(i=0; i<num; i++) {
|
||||
d = (struct packed_rrset_data*)list[i]->entry.data;
|
||||
if(list[i]->rk.type != htons(LDNS_RR_TYPE_NSEC3))
|
||||
|
@ -1304,7 +1460,8 @@ list_is_secure(struct module_env* env, struct val_env* ve,
|
|||
if(d->security == sec_status_secure)
|
||||
continue;
|
||||
d->security = val_verify_rrset_entry(env, ve, list[i], kkey,
|
||||
reason, reason_bogus, LDNS_SECTION_AUTHORITY, qstate);
|
||||
reason, reason_bogus, LDNS_SECTION_AUTHORITY, qstate,
|
||||
&verified);
|
||||
if(d->security != sec_status_secure) {
|
||||
verbose(VERB_ALGO, "NSEC3 did not verify");
|
||||
return 0;
|
||||
|
@ -1318,13 +1475,16 @@ enum sec_status
|
|||
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)
|
||||
sldns_ede_code* reason_bogus, struct module_qstate* qstate,
|
||||
struct nsec3_cache_table* ct)
|
||||
{
|
||||
rbtree_type ct;
|
||||
struct nsec3_filter flt;
|
||||
struct ce_response ce;
|
||||
struct ub_packed_rrset_key* rrset;
|
||||
int rr;
|
||||
int calc = 0;
|
||||
enum sec_status sec;
|
||||
|
||||
log_assert(qinfo->qtype == LDNS_RR_TYPE_DS);
|
||||
|
||||
if(!list || num == 0 || !kkey || !key_entry_isgood(kkey)) {
|
||||
|
@ -1335,7 +1495,6 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
|
|||
*reason = "not all NSEC3 records secure";
|
||||
return sec_status_bogus; /* not all NSEC3 records secure */
|
||||
}
|
||||
rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
|
||||
filter_init(&flt, list, num, qinfo); /* init RR iterator */
|
||||
if(!flt.zone) {
|
||||
*reason = "no NSEC3 records";
|
||||
|
@ -1346,8 +1505,8 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
|
|||
|
||||
/* Look for a matching NSEC3 to qname -- this is the normal
|
||||
* NODATA case. */
|
||||
if(find_matching_nsec3(env, &flt, &ct, qinfo->qname, qinfo->qname_len,
|
||||
&rrset, &rr)) {
|
||||
if(find_matching_nsec3(env, &flt, ct, qinfo->qname, qinfo->qname_len,
|
||||
&rrset, &rr, &calc)) {
|
||||
/* If the matching NSEC3 has the SOA bit set, it is from
|
||||
* the wrong zone (the child instead of the parent). If
|
||||
* it has the DS bit set, then we were lied to. */
|
||||
|
@ -1370,10 +1529,24 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
|
|||
/* Otherwise, this proves no DS. */
|
||||
return sec_status_secure;
|
||||
}
|
||||
if(calc == MAX_NSEC3_ERRORS) {
|
||||
verbose(VERB_ALGO, "nsec3 provenods: all attempted hash "
|
||||
"calculations were erroneous while finding a matching "
|
||||
"NSEC3, bogus");
|
||||
return sec_status_bogus;
|
||||
} else if(calc >= MAX_NSEC3_CALCULATIONS) {
|
||||
verbose(VERB_ALGO, "nsec3 provenods: reached "
|
||||
"MAX_NSEC3_CALCULATIONS (%d) while finding a "
|
||||
"matching NSEC3, unchecked still",
|
||||
MAX_NSEC3_CALCULATIONS);
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
|
||||
/* Otherwise, we are probably in the opt-out case. */
|
||||
if(nsec3_prove_closest_encloser(env, &flt, &ct, qinfo, 1, &ce)
|
||||
!= sec_status_secure) {
|
||||
sec = nsec3_prove_closest_encloser(env, &flt, ct, qinfo, 1, &ce, &calc);
|
||||
if(sec == sec_status_unchecked) {
|
||||
return sec_status_unchecked;
|
||||
} else if(sec != sec_status_secure) {
|
||||
/* an insecure delegation *above* the qname does not prove
|
||||
* anything about this qname exactly, and bogus is bogus */
|
||||
verbose(VERB_ALGO, "nsec3 provenods: did not match qname, "
|
||||
|
@ -1408,16 +1581,15 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
|
|||
enum sec_status
|
||||
nsec3_prove_nxornodata(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, int* nodata)
|
||||
struct query_info* qinfo, struct key_entry_key* kkey, int* nodata,
|
||||
struct nsec3_cache_table* ct, int* calc)
|
||||
{
|
||||
enum sec_status sec, secnx;
|
||||
rbtree_type ct;
|
||||
struct nsec3_filter flt;
|
||||
*nodata = 0;
|
||||
|
||||
if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
|
||||
return sec_status_bogus; /* no valid NSEC3s, bogus */
|
||||
rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
|
||||
filter_init(&flt, list, num, qinfo); /* init RR iterator */
|
||||
if(!flt.zone)
|
||||
return sec_status_bogus; /* no RRs */
|
||||
|
@ -1427,16 +1599,20 @@ nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve,
|
|||
/* try nxdomain and nodata after another, while keeping the
|
||||
* hash cache intact */
|
||||
|
||||
secnx = nsec3_do_prove_nameerror(env, &flt, &ct, qinfo);
|
||||
secnx = nsec3_do_prove_nameerror(env, &flt, ct, qinfo, calc);
|
||||
if(secnx==sec_status_secure)
|
||||
return sec_status_secure;
|
||||
sec = nsec3_do_prove_nodata(env, &flt, &ct, qinfo);
|
||||
else if(secnx == sec_status_unchecked)
|
||||
return sec_status_unchecked;
|
||||
sec = nsec3_do_prove_nodata(env, &flt, ct, qinfo, calc);
|
||||
if(sec==sec_status_secure) {
|
||||
*nodata = 1;
|
||||
} else if(sec == sec_status_insecure) {
|
||||
*nodata = 1;
|
||||
} else if(secnx == sec_status_insecure) {
|
||||
sec = sec_status_insecure;
|
||||
} else if(sec == sec_status_unchecked) {
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
return sec;
|
||||
}
|
||||
|
|
|
@ -98,6 +98,15 @@ struct sldns_buffer;
|
|||
/** The SHA1 hash algorithm for NSEC3 */
|
||||
#define NSEC3_HASH_SHA1 0x01
|
||||
|
||||
/**
|
||||
* Cache table for NSEC3 hashes.
|
||||
* It keeps a *pointer* to the region its items are allocated.
|
||||
*/
|
||||
struct nsec3_cache_table {
|
||||
rbtree_type* ct;
|
||||
struct regional* region;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine if the set of NSEC3 records provided with a response prove NAME
|
||||
* ERROR. This means that the NSEC3s prove a) the closest encloser exists,
|
||||
|
@ -110,14 +119,18 @@ struct sldns_buffer;
|
|||
* @param num: number of RRsets in the array to examine.
|
||||
* @param qinfo: query that is verified for.
|
||||
* @param kkey: key entry that signed the NSEC3s.
|
||||
* @param ct: cached hashes table.
|
||||
* @param calc: current hash calculations.
|
||||
* @return:
|
||||
* sec_status SECURE of the Name Error is proven by the NSEC3 RRs,
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored,
|
||||
* UNCHECKED if no more hash calculations are allowed at this point.
|
||||
*/
|
||||
enum sec_status
|
||||
nsec3_prove_nameerror(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);
|
||||
struct query_info* qinfo, struct key_entry_key* kkey,
|
||||
struct nsec3_cache_table* ct, int* calc);
|
||||
|
||||
/**
|
||||
* Determine if the NSEC3s provided in a response prove the NOERROR/NODATA
|
||||
|
@ -144,15 +157,18 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve,
|
|||
* @param num: number of RRsets in the array to examine.
|
||||
* @param qinfo: query that is verified for.
|
||||
* @param kkey: key entry that signed the NSEC3s.
|
||||
* @param ct: cached hashes table.
|
||||
* @param calc: current hash calculations.
|
||||
* @return:
|
||||
* sec_status SECURE of the proposition is proven by the NSEC3 RRs,
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored,
|
||||
* UNCHECKED if no more hash calculations are allowed at this point.
|
||||
*/
|
||||
enum sec_status
|
||||
nsec3_prove_nodata(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);
|
||||
|
||||
struct query_info* qinfo, struct key_entry_key* kkey,
|
||||
struct nsec3_cache_table* ct, int* calc);
|
||||
|
||||
/**
|
||||
* Prove that a positive wildcard match was appropriate (no direct match
|
||||
|
@ -166,14 +182,18 @@ nsec3_prove_nodata(struct module_env* env, struct val_env* ve,
|
|||
* @param kkey: key entry that signed the NSEC3s.
|
||||
* @param wc: The purported wildcard that matched. This is the wildcard name
|
||||
* as *.wildcard.name., with the *. label already removed.
|
||||
* @param ct: cached hashes table.
|
||||
* @param calc: current hash calculations.
|
||||
* @return:
|
||||
* sec_status SECURE of the proposition is proven by the NSEC3 RRs,
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored,
|
||||
* UNCHECKED if no more hash calculations are allowed at this point.
|
||||
*/
|
||||
enum sec_status
|
||||
nsec3_prove_wildcard(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, uint8_t* wc);
|
||||
struct query_info* qinfo, struct key_entry_key* kkey, uint8_t* wc,
|
||||
struct nsec3_cache_table* ct, int* calc);
|
||||
|
||||
/**
|
||||
* Prove that a DS response either had no DS, or wasn't a delegation point.
|
||||
|
@ -189,17 +209,20 @@ 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 ct: cached hashes table.
|
||||
* @return:
|
||||
* sec_status SECURE of the proposition is proven by the NSEC3 RRs,
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
|
||||
* or if there was no DS in an insecure (i.e., opt-in) way,
|
||||
* INDETERMINATE if it was clear that this wasn't a delegation point.
|
||||
* INDETERMINATE if it was clear that this wasn't a delegation point,
|
||||
* UNCHECKED if no more hash calculations are allowed at this point.
|
||||
*/
|
||||
enum sec_status
|
||||
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);
|
||||
sldns_ede_code* reason_bogus, struct module_qstate* qstate,
|
||||
struct nsec3_cache_table* ct);
|
||||
|
||||
/**
|
||||
* Prove NXDOMAIN or NODATA.
|
||||
|
@ -212,14 +235,18 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
|
|||
* @param kkey: key entry that signed the NSEC3s.
|
||||
* @param nodata: if return value is secure, this indicates if nodata or
|
||||
* nxdomain was proven.
|
||||
* @param ct: cached hashes table.
|
||||
* @param calc: current hash calculations.
|
||||
* @return:
|
||||
* sec_status SECURE of the proposition is proven by the NSEC3 RRs,
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored,
|
||||
* UNCHECKED if no more hash calculations are allowed at this point.
|
||||
*/
|
||||
enum sec_status
|
||||
nsec3_prove_nxornodata(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, int* nodata);
|
||||
struct query_info* qinfo, struct key_entry_key* kkey, int* nodata,
|
||||
struct nsec3_cache_table* ct, int* calc);
|
||||
|
||||
/**
|
||||
* The NSEC3 hash result storage.
|
||||
|
@ -256,6 +283,14 @@ struct nsec3_cached_hash {
|
|||
*/
|
||||
int nsec3_hash_cmp(const void* c1, const void* c2);
|
||||
|
||||
/**
|
||||
* Initialise the NSEC3 cache table.
|
||||
* @param ct: the nsec3 cache table.
|
||||
* @param region: the region where allocations for the table will happen.
|
||||
* @return true on success, false on malloc error.
|
||||
*/
|
||||
int nsec3_cache_table_init(struct nsec3_cache_table* ct, struct regional* region);
|
||||
|
||||
/**
|
||||
* Obtain the hash of an owner name.
|
||||
* Used internally by the nsec3 proof functions in this file.
|
||||
|
@ -272,7 +307,8 @@ int nsec3_hash_cmp(const void* c1, const void* c2);
|
|||
* @param dname_len: the length of the name.
|
||||
* @param hash: the hash node is returned on success.
|
||||
* @return:
|
||||
* 1 on success, either from cache or newly hashed hash is returned.
|
||||
* 2 on success, hash from cache is returned.
|
||||
* 1 on success, newly computed hash is returned.
|
||||
* 0 on a malloc failure.
|
||||
* -1 if the NSEC3 rr was badly formatted (i.e. formerr).
|
||||
*/
|
||||
|
|
|
@ -79,6 +79,9 @@
|
|||
#include <openssl/engine.h>
|
||||
#endif
|
||||
|
||||
/** Maximum number of RRSIG validations for an RRset. */
|
||||
#define MAX_VALIDATE_RRSIGS 8
|
||||
|
||||
/** return number of rrs in an rrset */
|
||||
static size_t
|
||||
rrset_get_count(struct ub_packed_rrset_key* rrset)
|
||||
|
@ -542,6 +545,8 @@ 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 numverified: incremented when the number of RRSIG validations
|
||||
* increases.
|
||||
* @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).
|
||||
|
@ -552,7 +557,8 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
|
|||
struct ub_packed_rrset_key* dnskey, size_t sig_idx,
|
||||
struct rbtree_type** sortree,
|
||||
char** reason, sldns_ede_code *reason_bogus,
|
||||
sldns_pkt_section section, struct module_qstate* qstate)
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
int* numverified)
|
||||
{
|
||||
/* find matching keys and check them */
|
||||
enum sec_status sec = sec_status_bogus;
|
||||
|
@ -576,6 +582,7 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
|
|||
tag != dnskey_calc_keytag(dnskey, i))
|
||||
continue;
|
||||
numchecked ++;
|
||||
(*numverified)++;
|
||||
|
||||
/* see if key verifies */
|
||||
sec = dnskey_verify_rrset_sig(env->scratch,
|
||||
|
@ -586,6 +593,13 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
|
|||
return sec;
|
||||
else if(sec == sec_status_indeterminate)
|
||||
numindeterminate ++;
|
||||
if(*numverified > MAX_VALIDATE_RRSIGS) {
|
||||
*reason = "too many RRSIG validations";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
verbose(VERB_ALGO, "verify sig: too many RRSIG validations");
|
||||
return sec_status_bogus;
|
||||
}
|
||||
}
|
||||
if(numchecked == 0) {
|
||||
*reason = "signatures from unknown keys";
|
||||
|
@ -609,7 +623,7 @@ 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)
|
||||
sldns_pkt_section section, struct module_qstate* qstate, int* verified)
|
||||
{
|
||||
enum sec_status sec;
|
||||
size_t i, num;
|
||||
|
@ -617,6 +631,7 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
/* make sure that for all DNSKEY algorithms there are valid sigs */
|
||||
struct algo_needs needs;
|
||||
int alg;
|
||||
*verified = 0;
|
||||
|
||||
num = rrset_get_sigcount(rrset);
|
||||
if(num == 0) {
|
||||
|
@ -641,7 +656,7 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
for(i=0; i<num; i++) {
|
||||
sec = dnskeyset_verify_rrset_sig(env, ve, *env->now, rrset,
|
||||
dnskey, i, &sortree, reason, reason_bogus,
|
||||
section, qstate);
|
||||
section, qstate, verified);
|
||||
/* see which algorithm has been fixed up */
|
||||
if(sec == sec_status_secure) {
|
||||
if(!sigalg)
|
||||
|
@ -653,6 +668,13 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
algo_needs_set_bogus(&needs,
|
||||
(uint8_t)rrset_get_sig_algo(rrset, i));
|
||||
}
|
||||
if(*verified > MAX_VALIDATE_RRSIGS) {
|
||||
verbose(VERB_QUERY, "rrset failed to verify, too many RRSIG validations");
|
||||
*reason = "too many RRSIG validations";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
return sec_status_bogus;
|
||||
}
|
||||
}
|
||||
if(sigalg && (alg=algo_needs_missing(&needs)) != 0) {
|
||||
verbose(VERB_ALGO, "rrset failed to verify: "
|
||||
|
@ -691,6 +713,7 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
int buf_canon = 0;
|
||||
uint16_t tag = dnskey_calc_keytag(dnskey, dnskey_idx);
|
||||
int algo = dnskey_get_algo(dnskey, dnskey_idx);
|
||||
int numverified = 0;
|
||||
|
||||
num = rrset_get_sigcount(rrset);
|
||||
if(num == 0) {
|
||||
|
@ -714,8 +737,16 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
if(sec == sec_status_secure)
|
||||
return sec;
|
||||
numchecked ++;
|
||||
numverified ++;
|
||||
if(sec == sec_status_indeterminate)
|
||||
numindeterminate ++;
|
||||
if(numverified > MAX_VALIDATE_RRSIGS) {
|
||||
verbose(VERB_QUERY, "rrset failed to verify, too many RRSIG validations");
|
||||
*reason = "too many RRSIG validations";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
return sec_status_bogus;
|
||||
}
|
||||
}
|
||||
verbose(VERB_ALGO, "rrset failed to verify: all signatures are bogus");
|
||||
if(!numchecked) {
|
||||
|
|
|
@ -260,6 +260,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 verified: if not NULL the number of RRSIG validations is returned.
|
||||
* @return SECURE if one key in the set verifies one rrsig.
|
||||
* UNCHECKED on allocation errors, unsupported algorithms, malformed data,
|
||||
* and BOGUS on verification failures (no keys match any signatures).
|
||||
|
@ -268,7 +269,7 @@ 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);
|
||||
sldns_pkt_section section, struct module_qstate* qstate, int* verified);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -58,6 +58,10 @@
|
|||
#include "sldns/wire2str.h"
|
||||
#include "sldns/parseutil.h"
|
||||
|
||||
/** Maximum allowed digest match failures per DS, for DNSKEYs with the same
|
||||
* properties */
|
||||
#define MAX_DS_MATCH_FAILURES 4
|
||||
|
||||
enum val_classification
|
||||
val_classify_response(uint16_t query_flags, struct query_info* origqinf,
|
||||
struct query_info* qinf, struct reply_info* rep, size_t skip)
|
||||
|
@ -336,7 +340,8 @@ static enum sec_status
|
|||
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)
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
int *verified)
|
||||
{
|
||||
enum sec_status sec;
|
||||
struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
|
||||
|
@ -346,6 +351,7 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
log_nametypeclass(VERB_ALGO, "verify rrset cached",
|
||||
rrset->rk.dname, ntohs(rrset->rk.type),
|
||||
ntohs(rrset->rk.rrset_class));
|
||||
*verified = 0;
|
||||
return d->security;
|
||||
}
|
||||
/* check in the cache if verification has already been done */
|
||||
|
@ -354,12 +360,13 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
log_nametypeclass(VERB_ALGO, "verify rrset from cache",
|
||||
rrset->rk.dname, ntohs(rrset->rk.type),
|
||||
ntohs(rrset->rk.rrset_class));
|
||||
*verified = 0;
|
||||
return d->security;
|
||||
}
|
||||
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);
|
||||
reason_bogus, section, qstate, verified);
|
||||
verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec));
|
||||
regional_free_all(env->scratch);
|
||||
|
||||
|
@ -393,7 +400,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)
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
int* verified)
|
||||
{
|
||||
/* temporary dnskey rrset-key */
|
||||
struct ub_packed_rrset_key dnskey;
|
||||
|
@ -407,7 +415,7 @@ 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);
|
||||
reason_bogus, section, qstate, verified);
|
||||
return sec;
|
||||
}
|
||||
|
||||
|
@ -439,6 +447,12 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
|
|||
if(!ds_digest_match_dnskey(env, dnskey_rrset, i, ds_rrset,
|
||||
ds_idx)) {
|
||||
verbose(VERB_ALGO, "DS match attempt failed");
|
||||
if(numchecked > numhashok + MAX_DS_MATCH_FAILURES) {
|
||||
verbose(VERB_ALGO, "DS match attempt reached "
|
||||
"MAX_DS_MATCH_FAILURES (%d); bogus",
|
||||
MAX_DS_MATCH_FAILURES);
|
||||
return sec_status_bogus;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
numhashok++;
|
||||
|
|
|
@ -124,12 +124,14 @@ 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 verified: if not NULL, the number of RRSIG validations is returned.
|
||||
* @return security status of verification.
|
||||
*/
|
||||
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);
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
int* verified);
|
||||
|
||||
/**
|
||||
* Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but
|
||||
|
|
|
@ -64,10 +64,15 @@
|
|||
#include "sldns/wire2str.h"
|
||||
#include "sldns/str2wire.h"
|
||||
|
||||
/** Max number of RRSIGs to validate at once, suspend query for later. */
|
||||
#define MAX_VALIDATE_AT_ONCE 8
|
||||
/** Max number of validation suspends allowed, error out otherwise. */
|
||||
#define MAX_VALIDATION_SUSPENDS 16
|
||||
|
||||
/* forward decl for cache response and normal super inform calls of a DS */
|
||||
static void process_ds_response(struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int id, int rcode, struct dns_msg* msg,
|
||||
struct query_info* qinfo, struct sock_list* origin);
|
||||
struct query_info* qinfo, struct sock_list* origin, int* suspend);
|
||||
|
||||
|
||||
/* Updates the suplied EDE (RFC8914) code selectively so we don't lose
|
||||
|
@ -112,7 +117,7 @@ fill_nsec3_iter(struct val_env* ve, char* s, int c)
|
|||
s = e;
|
||||
if(i>0 && ve->nsec3_keysize[i-1] >= ve->nsec3_keysize[i]) {
|
||||
log_err("nsec3 key iterations not ascending: %d %d",
|
||||
(int)ve->nsec3_keysize[i-1],
|
||||
(int)ve->nsec3_keysize[i-1],
|
||||
(int)ve->nsec3_keysize[i]);
|
||||
return 0;
|
||||
}
|
||||
|
@ -281,6 +286,21 @@ val_new(struct module_qstate* qstate, int id)
|
|||
return val_new_getmsg(qstate, vq);
|
||||
}
|
||||
|
||||
/** reset validator query state for query restart */
|
||||
static void
|
||||
val_restart(struct val_qstate* vq)
|
||||
{
|
||||
struct comm_timer* temp_timer;
|
||||
int restart_count;
|
||||
if(!vq) return;
|
||||
temp_timer = vq->suspend_timer;
|
||||
restart_count = vq->restart_count+1;
|
||||
memset(vq, 0, sizeof(*vq));
|
||||
vq->suspend_timer = temp_timer;
|
||||
vq->restart_count = restart_count;
|
||||
vq->state = VAL_INIT_STATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit validation with an error status
|
||||
*
|
||||
|
@ -587,30 +607,42 @@ prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
* completed.
|
||||
*
|
||||
* @param qstate: query state.
|
||||
* @param vq: validator query state.
|
||||
* @param env: module env for verify.
|
||||
* @param ve: validator env for verify.
|
||||
* @param qchase: query that was made.
|
||||
* @param chase_reply: answer to validate.
|
||||
* @param key_entry: the key entry, which is trusted, and which matches
|
||||
* the signer of the answer. The key entry isgood().
|
||||
* @param suspend: returned true if the task takes too long and needs to
|
||||
* suspend to continue the effort later.
|
||||
* @return false if any of the rrsets in the an or ns sections of the message
|
||||
* fail to verify. The message is then set to bogus.
|
||||
*/
|
||||
static int
|
||||
validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
|
||||
struct val_env* ve, struct query_info* qchase,
|
||||
struct reply_info* chase_reply, struct key_entry_key* key_entry)
|
||||
validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
struct module_env* env, struct val_env* ve, struct query_info* qchase,
|
||||
struct reply_info* chase_reply, struct key_entry_key* key_entry,
|
||||
int* suspend)
|
||||
{
|
||||
uint8_t* sname;
|
||||
size_t i, slen;
|
||||
struct ub_packed_rrset_key* s;
|
||||
enum sec_status sec;
|
||||
int dname_seen = 0;
|
||||
int dname_seen = 0, num_verifies = 0, verified, have_state = 0;
|
||||
char* reason = NULL;
|
||||
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
*suspend = 0;
|
||||
if(vq->msg_signatures_state) {
|
||||
/* Pick up the state, and reset it, may not be needed now. */
|
||||
vq->msg_signatures_state = 0;
|
||||
have_state = 1;
|
||||
}
|
||||
|
||||
/* validate the ANSWER section */
|
||||
for(i=0; i<chase_reply->an_numrrsets; i++) {
|
||||
if(have_state && i <= vq->msg_signatures_index)
|
||||
continue;
|
||||
s = chase_reply->rrsets[i];
|
||||
/* Skip the CNAME following a (validated) DNAME.
|
||||
* Because of the normalization routines in the iterator,
|
||||
|
@ -629,7 +661,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
|
|||
|
||||
/* Verify the answer rrset */
|
||||
sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
|
||||
&reason_bogus, LDNS_SECTION_ANSWER, qstate);
|
||||
&reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified);
|
||||
/* If the (answer) rrset failed to validate, then this
|
||||
* message is BAD. */
|
||||
if(sec != sec_status_secure) {
|
||||
|
@ -654,14 +686,33 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
|
|||
ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME) {
|
||||
dname_seen = 1;
|
||||
}
|
||||
num_verifies += verified;
|
||||
if(num_verifies > MAX_VALIDATE_AT_ONCE &&
|
||||
i+1 < (env->cfg->val_clean_additional?
|
||||
chase_reply->an_numrrsets+chase_reply->ns_numrrsets:
|
||||
chase_reply->rrset_count)) {
|
||||
/* If the number of RRSIGs exceeds the maximum in
|
||||
* one go, suspend. Only suspend if there is a next
|
||||
* rrset to verify, i+1<loopmax. Store where to
|
||||
* continue later. */
|
||||
*suspend = 1;
|
||||
vq->msg_signatures_state = 1;
|
||||
vq->msg_signatures_index = i;
|
||||
verbose(VERB_ALGO, "msg signature validation "
|
||||
"suspended");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* validate the AUTHORITY section */
|
||||
for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
|
||||
chase_reply->ns_numrrsets; i++) {
|
||||
if(have_state && i <= vq->msg_signatures_index)
|
||||
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,
|
||||
&verified);
|
||||
/* If anything in the authority section fails to be secure,
|
||||
* we have a bad message. */
|
||||
if(sec != sec_status_secure) {
|
||||
|
@ -675,6 +726,18 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
|
|||
update_reason_bogus(chase_reply, reason_bogus);
|
||||
return 0;
|
||||
}
|
||||
num_verifies += verified;
|
||||
if(num_verifies > MAX_VALIDATE_AT_ONCE &&
|
||||
i+1 < (env->cfg->val_clean_additional?
|
||||
chase_reply->an_numrrsets+chase_reply->ns_numrrsets:
|
||||
chase_reply->rrset_count)) {
|
||||
*suspend = 1;
|
||||
vq->msg_signatures_state = 1;
|
||||
vq->msg_signatures_index = i;
|
||||
verbose(VERB_ALGO, "msg signature validation "
|
||||
"suspended");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If set, the validator should clean the additional section of
|
||||
|
@ -684,22 +747,103 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
|
|||
/* attempt to validate the ADDITIONAL section rrsets */
|
||||
for(i=chase_reply->an_numrrsets+chase_reply->ns_numrrsets;
|
||||
i<chase_reply->rrset_count; i++) {
|
||||
if(have_state && i <= vq->msg_signatures_index)
|
||||
continue;
|
||||
s = chase_reply->rrsets[i];
|
||||
/* only validate rrs that have signatures with the key */
|
||||
/* leave others unchecked, those get removed later on too */
|
||||
val_find_rrset_signer(s, &sname, &slen);
|
||||
|
||||
verified = 0;
|
||||
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);
|
||||
&reason, NULL, LDNS_SECTION_ADDITIONAL, qstate,
|
||||
&verified);
|
||||
/* the additional section can fail to be secure,
|
||||
* it is optional, check signature in case we need
|
||||
* to clean the additional section later. */
|
||||
num_verifies += verified;
|
||||
if(num_verifies > MAX_VALIDATE_AT_ONCE &&
|
||||
i+1 < chase_reply->rrset_count) {
|
||||
*suspend = 1;
|
||||
vq->msg_signatures_state = 1;
|
||||
vq->msg_signatures_index = i;
|
||||
verbose(VERB_ALGO, "msg signature validation "
|
||||
"suspended");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
validate_suspend_timer_cb(void* arg)
|
||||
{
|
||||
struct module_qstate* qstate = (struct module_qstate*)arg;
|
||||
verbose(VERB_ALGO, "validate_suspend timer, continue");
|
||||
mesh_run(qstate->env->mesh, qstate->mesh_info, module_event_pass,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/** Setup timer to continue validation of msg signatures later */
|
||||
static int
|
||||
validate_suspend_setup_timer(struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int id, enum val_state resume_state)
|
||||
{
|
||||
struct timeval tv;
|
||||
int usec, slack, base;
|
||||
if(vq->suspend_count >= MAX_VALIDATION_SUSPENDS) {
|
||||
verbose(VERB_ALGO, "validate_suspend timer: "
|
||||
"reached MAX_VALIDATION_SUSPENDS (%d); error out",
|
||||
MAX_VALIDATION_SUSPENDS);
|
||||
errinf(qstate, "max validation suspends reached, "
|
||||
"too many RRSIG validations");
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "validate_suspend timer, set for suspend");
|
||||
vq->state = resume_state;
|
||||
qstate->ext_state[id] = module_wait_reply;
|
||||
if(!vq->suspend_timer) {
|
||||
vq->suspend_timer = comm_timer_create(
|
||||
qstate->env->worker_base,
|
||||
validate_suspend_timer_cb, qstate);
|
||||
if(!vq->suspend_timer) {
|
||||
log_err("validate_suspend_setup_timer: "
|
||||
"out of memory for comm_timer_create");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* The timer is activated later, after other events in the event
|
||||
* loop have been processed. The query state can also be deleted,
|
||||
* when the list is full and query states are dropped. */
|
||||
/* Extend wait time if there are a lot of queries or if this one
|
||||
* is taking long, to keep around cpu time for ordinary queries. */
|
||||
usec = 50000; /* 50 msec */
|
||||
slack = 0;
|
||||
if(qstate->env->mesh->all.count >= qstate->env->mesh->max_reply_states)
|
||||
slack += 3;
|
||||
else if(qstate->env->mesh->all.count >= qstate->env->mesh->max_reply_states/2)
|
||||
slack += 2;
|
||||
else if(qstate->env->mesh->all.count >= qstate->env->mesh->max_reply_states/4)
|
||||
slack += 1;
|
||||
if(vq->suspend_count > 3)
|
||||
slack += 3;
|
||||
else if(vq->suspend_count > 0)
|
||||
slack += vq->suspend_count;
|
||||
if(slack != 0 && slack <= 12 /* No numeric overflow. */) {
|
||||
usec = usec << slack;
|
||||
}
|
||||
/* Spread such timeouts within 90%-100% of the original timer. */
|
||||
base = usec * 9/10;
|
||||
usec = base + ub_random_max(qstate->env->rnd, usec-base);
|
||||
tv.tv_usec = (usec % 1000000);
|
||||
tv.tv_sec = (usec / 1000000);
|
||||
vq->suspend_count ++;
|
||||
comm_timer_set(vq->suspend_timer, &tv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect wrong truncated response (say from BIND 9.6.1 that is forwarding
|
||||
* and saw the NS record without signatures from a referral).
|
||||
|
@ -798,11 +942,17 @@ remove_spurious_authority(struct reply_info* chase_reply,
|
|||
* @param chase_reply: answer to that query to validate.
|
||||
* @param kkey: the key entry, which is trusted, and which matches
|
||||
* the signer of the answer. The key entry isgood().
|
||||
* @param qstate: query state for the region.
|
||||
* @param vq: validator state for the nsec3 cache table.
|
||||
* @param nsec3_calculations: current nsec3 hash calculations.
|
||||
* @param suspend: returned true if the task takes too long and needs to
|
||||
* suspend to continue the effort later.
|
||||
*/
|
||||
static void
|
||||
validate_positive_response(struct module_env* env, struct val_env* ve,
|
||||
struct query_info* qchase, struct reply_info* chase_reply,
|
||||
struct key_entry_key* kkey)
|
||||
struct key_entry_key* kkey, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int* nsec3_calculations, int* suspend)
|
||||
{
|
||||
uint8_t* wc = NULL;
|
||||
size_t wl;
|
||||
|
@ -811,6 +961,7 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
|
|||
int nsec3s_seen = 0;
|
||||
size_t i;
|
||||
struct ub_packed_rrset_key* s;
|
||||
*suspend = 0;
|
||||
|
||||
/* validate the ANSWER section - this will be the answer itself */
|
||||
for(i=0; i<chase_reply->an_numrrsets; i++) {
|
||||
|
@ -862,17 +1013,23 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
|
|||
/* If this was a positive wildcard response that we haven't already
|
||||
* proven, and we have NSEC3 records, try to prove it using the NSEC3
|
||||
* records. */
|
||||
if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) {
|
||||
if(wc != NULL && !wc_NSEC_ok && nsec3s_seen &&
|
||||
nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) {
|
||||
enum sec_status sec = nsec3_prove_wildcard(env, ve,
|
||||
chase_reply->rrsets+chase_reply->an_numrrsets,
|
||||
chase_reply->ns_numrrsets, qchase, kkey, wc);
|
||||
chase_reply->ns_numrrsets, qchase, kkey, wc,
|
||||
&vq->nsec3_cache_table, nsec3_calculations);
|
||||
if(sec == sec_status_insecure) {
|
||||
verbose(VERB_ALGO, "Positive wildcard response is "
|
||||
"insecure");
|
||||
chase_reply->security = sec_status_insecure;
|
||||
return;
|
||||
} else if(sec == sec_status_secure)
|
||||
} else if(sec == sec_status_secure) {
|
||||
wc_NSEC_ok = 1;
|
||||
} else if(sec == sec_status_unchecked) {
|
||||
*suspend = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If after all this, we still haven't proven the positive wildcard
|
||||
|
@ -904,11 +1061,17 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
|
|||
* @param chase_reply: answer to that query to validate.
|
||||
* @param kkey: the key entry, which is trusted, and which matches
|
||||
* the signer of the answer. The key entry isgood().
|
||||
* @param qstate: query state for the region.
|
||||
* @param vq: validator state for the nsec3 cache table.
|
||||
* @param nsec3_calculations: current nsec3 hash calculations.
|
||||
* @param suspend: returned true if the task takes too long and needs to
|
||||
* suspend to continue the effort later.
|
||||
*/
|
||||
static void
|
||||
validate_nodata_response(struct module_env* env, struct val_env* ve,
|
||||
struct query_info* qchase, struct reply_info* chase_reply,
|
||||
struct key_entry_key* kkey)
|
||||
struct key_entry_key* kkey, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int* nsec3_calculations, int* suspend)
|
||||
{
|
||||
/* Since we are here, there must be nothing in the ANSWER section to
|
||||
* validate. */
|
||||
|
@ -925,6 +1088,7 @@ validate_nodata_response(struct module_env* env, struct val_env* ve,
|
|||
int nsec3s_seen = 0; /* nsec3s seen */
|
||||
struct ub_packed_rrset_key* s;
|
||||
size_t i;
|
||||
*suspend = 0;
|
||||
|
||||
for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
|
||||
chase_reply->ns_numrrsets; i++) {
|
||||
|
@ -963,16 +1127,23 @@ validate_nodata_response(struct module_env* env, struct val_env* ve,
|
|||
}
|
||||
}
|
||||
|
||||
if(!has_valid_nsec && nsec3s_seen) {
|
||||
if(!has_valid_nsec && nsec3s_seen &&
|
||||
nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) {
|
||||
enum sec_status sec = nsec3_prove_nodata(env, ve,
|
||||
chase_reply->rrsets+chase_reply->an_numrrsets,
|
||||
chase_reply->ns_numrrsets, qchase, kkey);
|
||||
chase_reply->ns_numrrsets, qchase, kkey,
|
||||
&vq->nsec3_cache_table, nsec3_calculations);
|
||||
if(sec == sec_status_insecure) {
|
||||
verbose(VERB_ALGO, "NODATA response is insecure");
|
||||
chase_reply->security = sec_status_insecure;
|
||||
return;
|
||||
} else if(sec == sec_status_secure)
|
||||
} else if(sec == sec_status_secure) {
|
||||
has_valid_nsec = 1;
|
||||
} else if(sec == sec_status_unchecked) {
|
||||
/* check is incomplete; suspend */
|
||||
*suspend = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!has_valid_nsec) {
|
||||
|
@ -1004,11 +1175,18 @@ validate_nodata_response(struct module_env* env, struct val_env* ve,
|
|||
* @param kkey: the key entry, which is trusted, and which matches
|
||||
* the signer of the answer. The key entry isgood().
|
||||
* @param rcode: adjusted RCODE, in case of RCODE/proof mismatch leniency.
|
||||
* @param qstate: query state for the region.
|
||||
* @param vq: validator state for the nsec3 cache table.
|
||||
* @param nsec3_calculations: current nsec3 hash calculations.
|
||||
* @param suspend: returned true if the task takes too long and needs to
|
||||
* suspend to continue the effort later.
|
||||
*/
|
||||
static void
|
||||
validate_nameerror_response(struct module_env* env, struct val_env* ve,
|
||||
struct query_info* qchase, struct reply_info* chase_reply,
|
||||
struct key_entry_key* kkey, int* rcode)
|
||||
struct key_entry_key* kkey, int* rcode,
|
||||
struct module_qstate* qstate, struct val_qstate* vq,
|
||||
int* nsec3_calculations, int* suspend)
|
||||
{
|
||||
int has_valid_nsec = 0;
|
||||
int has_valid_wnsec = 0;
|
||||
|
@ -1018,6 +1196,7 @@ validate_nameerror_response(struct module_env* env, struct val_env* ve,
|
|||
uint8_t* ce;
|
||||
int ce_labs = 0;
|
||||
int prev_ce_labs = 0;
|
||||
*suspend = 0;
|
||||
|
||||
for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
|
||||
chase_reply->ns_numrrsets; i++) {
|
||||
|
@ -1047,13 +1226,18 @@ validate_nameerror_response(struct module_env* env, struct val_env* ve,
|
|||
nsec3s_seen = 1;
|
||||
}
|
||||
|
||||
if((!has_valid_nsec || !has_valid_wnsec) && nsec3s_seen) {
|
||||
if((!has_valid_nsec || !has_valid_wnsec) && nsec3s_seen &&
|
||||
nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) {
|
||||
/* use NSEC3 proof, both answer and auth rrsets, in case
|
||||
* NSEC3s end up in the answer (due to qtype=NSEC3 or so) */
|
||||
chase_reply->security = nsec3_prove_nameerror(env, ve,
|
||||
chase_reply->rrsets, chase_reply->an_numrrsets+
|
||||
chase_reply->ns_numrrsets, qchase, kkey);
|
||||
if(chase_reply->security != sec_status_secure) {
|
||||
chase_reply->ns_numrrsets, qchase, kkey,
|
||||
&vq->nsec3_cache_table, nsec3_calculations);
|
||||
if(chase_reply->security == sec_status_unchecked) {
|
||||
*suspend = 1;
|
||||
return;
|
||||
} else if(chase_reply->security != sec_status_secure) {
|
||||
verbose(VERB_QUERY, "NameError response failed nsec, "
|
||||
"nsec3 proof was %s", sec_status_to_string(
|
||||
chase_reply->security));
|
||||
|
@ -1065,26 +1249,34 @@ validate_nameerror_response(struct module_env* env, struct val_env* ve,
|
|||
|
||||
/* If the message fails to prove either condition, it is bogus. */
|
||||
if(!has_valid_nsec) {
|
||||
validate_nodata_response(env, ve, qchase, chase_reply, kkey,
|
||||
qstate, vq, nsec3_calculations, suspend);
|
||||
if(*suspend) return;
|
||||
verbose(VERB_QUERY, "NameError response has failed to prove: "
|
||||
"qname does not exist");
|
||||
chase_reply->security = sec_status_bogus;
|
||||
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
|
||||
/* Be lenient with RCODE in NSEC NameError responses */
|
||||
validate_nodata_response(env, ve, qchase, chase_reply, kkey);
|
||||
if (chase_reply->security == sec_status_secure)
|
||||
if(chase_reply->security == sec_status_secure) {
|
||||
*rcode = LDNS_RCODE_NOERROR;
|
||||
} else {
|
||||
chase_reply->security = sec_status_bogus;
|
||||
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!has_valid_wnsec) {
|
||||
validate_nodata_response(env, ve, qchase, chase_reply, kkey,
|
||||
qstate, vq, nsec3_calculations, suspend);
|
||||
if(*suspend) return;
|
||||
verbose(VERB_QUERY, "NameError response has failed to prove: "
|
||||
"covering wildcard does not exist");
|
||||
chase_reply->security = sec_status_bogus;
|
||||
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
|
||||
/* Be lenient with RCODE in NSEC NameError responses */
|
||||
validate_nodata_response(env, ve, qchase, chase_reply, kkey);
|
||||
if (chase_reply->security == sec_status_secure)
|
||||
if (chase_reply->security == sec_status_secure) {
|
||||
*rcode = LDNS_RCODE_NOERROR;
|
||||
} else {
|
||||
chase_reply->security = sec_status_bogus;
|
||||
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1144,11 +1336,17 @@ validate_referral_response(struct reply_info* chase_reply)
|
|||
* @param chase_reply: answer to that query to validate.
|
||||
* @param kkey: the key entry, which is trusted, and which matches
|
||||
* the signer of the answer. The key entry isgood().
|
||||
* @param qstate: query state for the region.
|
||||
* @param vq: validator state for the nsec3 cache table.
|
||||
* @param nsec3_calculations: current nsec3 hash calculations.
|
||||
* @param suspend: returned true if the task takes too long and needs to
|
||||
* suspend to continue the effort later.
|
||||
*/
|
||||
static void
|
||||
validate_any_response(struct module_env* env, struct val_env* ve,
|
||||
struct query_info* qchase, struct reply_info* chase_reply,
|
||||
struct key_entry_key* kkey)
|
||||
struct key_entry_key* kkey, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int* nsec3_calculations, int* suspend)
|
||||
{
|
||||
/* all answer and auth rrsets already verified */
|
||||
/* but check if a wildcard response is given, then check NSEC/NSEC3
|
||||
|
@ -1159,6 +1357,7 @@ validate_any_response(struct module_env* env, struct val_env* ve,
|
|||
int nsec3s_seen = 0;
|
||||
size_t i;
|
||||
struct ub_packed_rrset_key* s;
|
||||
*suspend = 0;
|
||||
|
||||
if(qchase->qtype != LDNS_RR_TYPE_ANY) {
|
||||
log_err("internal error: ANY validation called for non-ANY");
|
||||
|
@ -1213,19 +1412,25 @@ validate_any_response(struct module_env* env, struct val_env* ve,
|
|||
/* If this was a positive wildcard response that we haven't already
|
||||
* proven, and we have NSEC3 records, try to prove it using the NSEC3
|
||||
* records. */
|
||||
if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) {
|
||||
if(wc != NULL && !wc_NSEC_ok && nsec3s_seen &&
|
||||
nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) {
|
||||
/* look both in answer and auth section for NSEC3s */
|
||||
enum sec_status sec = nsec3_prove_wildcard(env, ve,
|
||||
chase_reply->rrsets,
|
||||
chase_reply->an_numrrsets+chase_reply->ns_numrrsets,
|
||||
qchase, kkey, wc);
|
||||
qchase, kkey, wc, &vq->nsec3_cache_table,
|
||||
nsec3_calculations);
|
||||
if(sec == sec_status_insecure) {
|
||||
verbose(VERB_ALGO, "Positive ANY wildcard response is "
|
||||
"insecure");
|
||||
chase_reply->security = sec_status_insecure;
|
||||
return;
|
||||
} else if(sec == sec_status_secure)
|
||||
} else if(sec == sec_status_secure) {
|
||||
wc_NSEC_ok = 1;
|
||||
} else if(sec == sec_status_unchecked) {
|
||||
*suspend = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If after all this, we still haven't proven the positive wildcard
|
||||
|
@ -1258,11 +1463,17 @@ validate_any_response(struct module_env* env, struct val_env* ve,
|
|||
* @param chase_reply: answer to that query to validate.
|
||||
* @param kkey: the key entry, which is trusted, and which matches
|
||||
* the signer of the answer. The key entry isgood().
|
||||
* @param qstate: query state for the region.
|
||||
* @param vq: validator state for the nsec3 cache table.
|
||||
* @param nsec3_calculations: current nsec3 hash calculations.
|
||||
* @param suspend: returned true if the task takes too long and needs to
|
||||
* suspend to continue the effort later.
|
||||
*/
|
||||
static void
|
||||
validate_cname_response(struct module_env* env, struct val_env* ve,
|
||||
struct query_info* qchase, struct reply_info* chase_reply,
|
||||
struct key_entry_key* kkey)
|
||||
struct key_entry_key* kkey, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int* nsec3_calculations, int* suspend)
|
||||
{
|
||||
uint8_t* wc = NULL;
|
||||
size_t wl;
|
||||
|
@ -1270,6 +1481,7 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
|
|||
int nsec3s_seen = 0;
|
||||
size_t i;
|
||||
struct ub_packed_rrset_key* s;
|
||||
*suspend = 0;
|
||||
|
||||
/* validate the ANSWER section - this will be the CNAME (+DNAME) */
|
||||
for(i=0; i<chase_reply->an_numrrsets; i++) {
|
||||
|
@ -1334,17 +1546,23 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
|
|||
/* If this was a positive wildcard response that we haven't already
|
||||
* proven, and we have NSEC3 records, try to prove it using the NSEC3
|
||||
* records. */
|
||||
if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) {
|
||||
if(wc != NULL && !wc_NSEC_ok && nsec3s_seen &&
|
||||
nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) {
|
||||
enum sec_status sec = nsec3_prove_wildcard(env, ve,
|
||||
chase_reply->rrsets+chase_reply->an_numrrsets,
|
||||
chase_reply->ns_numrrsets, qchase, kkey, wc);
|
||||
chase_reply->ns_numrrsets, qchase, kkey, wc,
|
||||
&vq->nsec3_cache_table, nsec3_calculations);
|
||||
if(sec == sec_status_insecure) {
|
||||
verbose(VERB_ALGO, "wildcard CNAME response is "
|
||||
"insecure");
|
||||
chase_reply->security = sec_status_insecure;
|
||||
return;
|
||||
} else if(sec == sec_status_secure)
|
||||
} else if(sec == sec_status_secure) {
|
||||
wc_NSEC_ok = 1;
|
||||
} else if(sec == sec_status_unchecked) {
|
||||
*suspend = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If after all this, we still haven't proven the positive wildcard
|
||||
|
@ -1375,11 +1593,17 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
|
|||
* @param chase_reply: answer to that query to validate.
|
||||
* @param kkey: the key entry, which is trusted, and which matches
|
||||
* the signer of the answer. The key entry isgood().
|
||||
* @param qstate: query state for the region.
|
||||
* @param vq: validator state for the nsec3 cache table.
|
||||
* @param nsec3_calculations: current nsec3 hash calculations.
|
||||
* @param suspend: returned true if the task takes too long and needs to
|
||||
* suspend to continue the effort later.
|
||||
*/
|
||||
static void
|
||||
validate_cname_noanswer_response(struct module_env* env, struct val_env* ve,
|
||||
struct query_info* qchase, struct reply_info* chase_reply,
|
||||
struct key_entry_key* kkey)
|
||||
struct key_entry_key* kkey, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int* nsec3_calculations, int* suspend)
|
||||
{
|
||||
int nodata_valid_nsec = 0; /* If true, then NODATA has been proven.*/
|
||||
uint8_t* ce = NULL; /* for wildcard nodata responses. This is the
|
||||
|
@ -1393,6 +1617,7 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve,
|
|||
uint8_t* nsec_ce; /* Used to find the NSEC with the longest ce */
|
||||
int ce_labs = 0;
|
||||
int prev_ce_labs = 0;
|
||||
*suspend = 0;
|
||||
|
||||
/* the AUTHORITY section */
|
||||
for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
|
||||
|
@ -1458,11 +1683,13 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve,
|
|||
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
|
||||
return;
|
||||
}
|
||||
if(!nodata_valid_nsec && !nxdomain_valid_nsec && nsec3s_seen) {
|
||||
if(!nodata_valid_nsec && !nxdomain_valid_nsec && nsec3s_seen &&
|
||||
nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) {
|
||||
int nodata;
|
||||
enum sec_status sec = nsec3_prove_nxornodata(env, ve,
|
||||
chase_reply->rrsets+chase_reply->an_numrrsets,
|
||||
chase_reply->ns_numrrsets, qchase, kkey, &nodata);
|
||||
chase_reply->ns_numrrsets, qchase, kkey, &nodata,
|
||||
&vq->nsec3_cache_table, nsec3_calculations);
|
||||
if(sec == sec_status_insecure) {
|
||||
verbose(VERB_ALGO, "CNAMEchain to noanswer response "
|
||||
"is insecure");
|
||||
|
@ -1472,6 +1699,9 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve,
|
|||
if(nodata)
|
||||
nodata_valid_nsec = 1;
|
||||
else nxdomain_valid_nsec = 1;
|
||||
} else if(sec == sec_status_unchecked) {
|
||||
*suspend = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1815,13 +2045,37 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
|
|||
* Uses negative cache for NSEC3 lookup of DS responses. */
|
||||
/* only if cache not blacklisted, of course */
|
||||
struct dns_msg* msg;
|
||||
if(!qstate->blacklist && !vq->chain_blacklist &&
|
||||
int suspend;
|
||||
if(vq->sub_ds_msg) {
|
||||
/* We have a suspended DS reply from a sub-query;
|
||||
* process it. */
|
||||
verbose(VERB_ALGO, "Process suspended sub DS response");
|
||||
msg = vq->sub_ds_msg;
|
||||
process_ds_response(qstate, vq, id, LDNS_RCODE_NOERROR,
|
||||
msg, &msg->qinfo, NULL, &suspend);
|
||||
if(suspend) {
|
||||
/* we'll come back here later to continue */
|
||||
if(!validate_suspend_setup_timer(qstate, vq,
|
||||
id, VAL_FINDKEY_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
vq->sub_ds_msg = NULL;
|
||||
return 1; /* continue processing ds-response results */
|
||||
} else if(!qstate->blacklist && !vq->chain_blacklist &&
|
||||
(msg=val_find_DS(qstate->env, target_key_name,
|
||||
target_key_len, vq->qchase.qclass, qstate->region,
|
||||
vq->key_entry->name)) ) {
|
||||
verbose(VERB_ALGO, "Process cached DS response");
|
||||
process_ds_response(qstate, vq, id, LDNS_RCODE_NOERROR,
|
||||
msg, &msg->qinfo, NULL);
|
||||
msg, &msg->qinfo, NULL, &suspend);
|
||||
if(suspend) {
|
||||
/* we'll come back here later to continue */
|
||||
if(!validate_suspend_setup_timer(qstate, vq,
|
||||
id, VAL_FINDKEY_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
return 1; /* continue processing ds-response results */
|
||||
}
|
||||
if(!generate_request(qstate, id, target_key_name,
|
||||
|
@ -1864,7 +2118,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
struct val_env* ve, int id)
|
||||
{
|
||||
enum val_classification subtype;
|
||||
int rcode;
|
||||
int rcode, suspend, nsec3_calculations = 0;
|
||||
|
||||
if(!vq->key_entry) {
|
||||
verbose(VERB_ALGO, "validate: no key entry, failed");
|
||||
|
@ -1921,8 +2175,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
|
||||
/* check signatures in the message;
|
||||
* answer and authority must be valid, additional is only checked. */
|
||||
if(!validate_msg_signatures(qstate, qstate->env, ve, &vq->qchase,
|
||||
vq->chase_reply, vq->key_entry)) {
|
||||
if(!validate_msg_signatures(qstate, vq, qstate->env, ve, &vq->qchase,
|
||||
vq->chase_reply, vq->key_entry, &suspend)) {
|
||||
if(suspend) {
|
||||
if(!validate_suspend_setup_timer(qstate, vq,
|
||||
id, VAL_VALIDATE_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
/* workaround bad recursor out there that truncates (even
|
||||
* with EDNS4k) to 512 by removing RRSIG from auth section
|
||||
* for positive replies*/
|
||||
|
@ -1951,7 +2211,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
case VAL_CLASS_POSITIVE:
|
||||
verbose(VERB_ALGO, "Validating a positive response");
|
||||
validate_positive_response(qstate->env, ve,
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry);
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry,
|
||||
qstate, vq, &nsec3_calculations, &suspend);
|
||||
if(suspend) {
|
||||
if(!validate_suspend_setup_timer(qstate,
|
||||
vq, id, VAL_VALIDATE_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_DETAIL, "validate(positive): %s",
|
||||
sec_status_to_string(
|
||||
vq->chase_reply->security));
|
||||
|
@ -1960,7 +2227,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
case VAL_CLASS_NODATA:
|
||||
verbose(VERB_ALGO, "Validating a nodata response");
|
||||
validate_nodata_response(qstate->env, ve,
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry);
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry,
|
||||
qstate, vq, &nsec3_calculations, &suspend);
|
||||
if(suspend) {
|
||||
if(!validate_suspend_setup_timer(qstate,
|
||||
vq, id, VAL_VALIDATE_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_DETAIL, "validate(nodata): %s",
|
||||
sec_status_to_string(
|
||||
vq->chase_reply->security));
|
||||
|
@ -1970,7 +2244,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
rcode = (int)FLAGS_GET_RCODE(vq->orig_msg->rep->flags);
|
||||
verbose(VERB_ALGO, "Validating a nxdomain response");
|
||||
validate_nameerror_response(qstate->env, ve,
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry, &rcode);
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry, &rcode,
|
||||
qstate, vq, &nsec3_calculations, &suspend);
|
||||
if(suspend) {
|
||||
if(!validate_suspend_setup_timer(qstate,
|
||||
vq, id, VAL_VALIDATE_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_DETAIL, "validate(nxdomain): %s",
|
||||
sec_status_to_string(
|
||||
vq->chase_reply->security));
|
||||
|
@ -1981,7 +2262,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
case VAL_CLASS_CNAME:
|
||||
verbose(VERB_ALGO, "Validating a cname response");
|
||||
validate_cname_response(qstate->env, ve,
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry);
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry,
|
||||
qstate, vq, &nsec3_calculations, &suspend);
|
||||
if(suspend) {
|
||||
if(!validate_suspend_setup_timer(qstate,
|
||||
vq, id, VAL_VALIDATE_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_DETAIL, "validate(cname): %s",
|
||||
sec_status_to_string(
|
||||
vq->chase_reply->security));
|
||||
|
@ -1991,7 +2279,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
verbose(VERB_ALGO, "Validating a cname noanswer "
|
||||
"response");
|
||||
validate_cname_noanswer_response(qstate->env, ve,
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry);
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry,
|
||||
qstate, vq, &nsec3_calculations, &suspend);
|
||||
if(suspend) {
|
||||
if(!validate_suspend_setup_timer(qstate,
|
||||
vq, id, VAL_VALIDATE_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_DETAIL, "validate(cname_noanswer): %s",
|
||||
sec_status_to_string(
|
||||
vq->chase_reply->security));
|
||||
|
@ -2009,7 +2304,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
verbose(VERB_ALGO, "Validating a positive ANY "
|
||||
"response");
|
||||
validate_any_response(qstate->env, ve, &vq->qchase,
|
||||
vq->chase_reply, vq->key_entry);
|
||||
vq->chase_reply, vq->key_entry, qstate, vq,
|
||||
&nsec3_calculations, &suspend);
|
||||
if(suspend) {
|
||||
if(!validate_suspend_setup_timer(qstate,
|
||||
vq, id, VAL_VALIDATE_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_DETAIL, "validate(positive_any): %s",
|
||||
sec_status_to_string(
|
||||
vq->chase_reply->security));
|
||||
|
@ -2118,16 +2420,13 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
if(vq->orig_msg->rep->security == sec_status_bogus) {
|
||||
/* see if we can try again to fetch data */
|
||||
if(vq->restart_count < ve->max_restart) {
|
||||
int restart_count = vq->restart_count+1;
|
||||
verbose(VERB_ALGO, "validation failed, "
|
||||
"blacklist and retry to fetch data");
|
||||
val_blacklist(&qstate->blacklist, qstate->region,
|
||||
qstate->reply_origin, 0);
|
||||
qstate->reply_origin = NULL;
|
||||
qstate->errinf = NULL;
|
||||
memset(vq, 0, sizeof(*vq));
|
||||
vq->restart_count = restart_count;
|
||||
vq->state = VAL_INIT_STATE;
|
||||
val_restart(vq);
|
||||
verbose(VERB_ALGO, "pass back to next module");
|
||||
qstate->ext_state[id] = module_restart_next;
|
||||
return 0;
|
||||
|
@ -2454,7 +2753,10 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
|
|||
* DS response indicated an end to secure space, is_good if the DS
|
||||
* validated. It returns ke=NULL if the DS response indicated that the
|
||||
* request wasn't a delegation point.
|
||||
* @return 0 on servfail error (malloc failure).
|
||||
* @return
|
||||
* 0 on success,
|
||||
* 1 on servfail error (malloc failure),
|
||||
* 2 on NSEC3 suspend.
|
||||
*/
|
||||
static int
|
||||
ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
|
@ -2465,6 +2767,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
char* reason = NULL;
|
||||
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
enum val_classification subtype;
|
||||
int verified;
|
||||
if(rcode != LDNS_RCODE_NOERROR) {
|
||||
char rc[16];
|
||||
rc[0]=0;
|
||||
|
@ -2495,7 +2798,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
/* Verify only returns BOGUS or SECURE. If the rrset is
|
||||
* bogus, then we are done. */
|
||||
sec = val_verify_rrset_entry(qstate->env, ve, ds,
|
||||
vq->key_entry, &reason, &reason_bogus, LDNS_SECTION_ANSWER, qstate);
|
||||
vq->key_entry, &reason, &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified);
|
||||
if(sec != sec_status_secure) {
|
||||
verbose(VERB_DETAIL, "DS rrset in DS response did "
|
||||
"not verify");
|
||||
|
@ -2513,7 +2816,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
ub_packed_rrset_ttl(ds),
|
||||
LDNS_EDE_UNSUPPORTED_DS_DIGEST, NULL,
|
||||
*qstate->env->now);
|
||||
return (*ke) != NULL;
|
||||
return (*ke) == NULL;
|
||||
}
|
||||
|
||||
/* Otherwise, we return the positive response. */
|
||||
|
@ -2521,7 +2824,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
*ke = key_entry_create_rrset(qstate->region,
|
||||
qinfo->qname, qinfo->qname_len, qinfo->qclass, ds,
|
||||
NULL, LDNS_EDE_NONE, NULL, *qstate->env->now);
|
||||
return (*ke) != NULL;
|
||||
return (*ke) == NULL;
|
||||
} else if(subtype == VAL_CLASS_NODATA ||
|
||||
subtype == VAL_CLASS_NAMEERROR) {
|
||||
/* NODATA means that the qname exists, but that there was
|
||||
|
@ -2555,12 +2858,12 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
qinfo->qclass, proof_ttl,
|
||||
LDNS_EDE_NONE, NULL,
|
||||
*qstate->env->now);
|
||||
return (*ke) != NULL;
|
||||
return (*ke) == NULL;
|
||||
case sec_status_insecure:
|
||||
verbose(VERB_DETAIL, "NSEC RRset for the "
|
||||
"referral proved not a delegation point");
|
||||
*ke = NULL;
|
||||
return 1;
|
||||
return 0;
|
||||
case sec_status_bogus:
|
||||
verbose(VERB_DETAIL, "NSEC RRset for the "
|
||||
"referral did not prove no DS.");
|
||||
|
@ -2572,10 +2875,17 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
break;
|
||||
}
|
||||
|
||||
if(!nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) {
|
||||
log_err("malloc failure in ds_response_to_ke for "
|
||||
"NSEC3 cache");
|
||||
reason = "malloc failure";
|
||||
errinf_ede(qstate, reason, 0);
|
||||
goto return_bogus;
|
||||
}
|
||||
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);
|
||||
&reason_bogus, qstate, &vq->nsec3_cache_table);
|
||||
switch(sec) {
|
||||
case sec_status_insecure:
|
||||
/* case insecure also continues to unsigned
|
||||
|
@ -2589,18 +2899,19 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
qinfo->qclass, proof_ttl,
|
||||
LDNS_EDE_NONE, NULL,
|
||||
*qstate->env->now);
|
||||
return (*ke) != NULL;
|
||||
return (*ke) == NULL;
|
||||
case sec_status_indeterminate:
|
||||
verbose(VERB_DETAIL, "NSEC3s for the "
|
||||
"referral proved no delegation");
|
||||
*ke = NULL;
|
||||
return 1;
|
||||
return 0;
|
||||
case sec_status_bogus:
|
||||
verbose(VERB_DETAIL, "NSEC3s for the "
|
||||
"referral did not prove no DS.");
|
||||
errinf_ede(qstate, reason, reason_bogus);
|
||||
goto return_bogus;
|
||||
case sec_status_unchecked:
|
||||
return 2;
|
||||
default:
|
||||
/* NSEC3 proof did not work */
|
||||
break;
|
||||
|
@ -2641,13 +2952,13 @@ 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);
|
||||
LDNS_SECTION_ANSWER, qstate, &verified);
|
||||
if(sec == sec_status_secure) {
|
||||
verbose(VERB_ALGO, "CNAME validated, "
|
||||
"proof that DS does not exist");
|
||||
/* and that it is not a referral point */
|
||||
*ke = NULL;
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
errinf(qstate, "CNAME in DS response was not secure.");
|
||||
errinf_ede(qstate, reason, reason_bogus);
|
||||
|
@ -2671,7 +2982,7 @@ return_bogus:
|
|||
*ke = key_entry_create_bad(qstate->region, qinfo->qname,
|
||||
qinfo->qname_len, qinfo->qclass, BOGUS_KEY_TTL,
|
||||
reason_bogus, reason, *qstate->env->now);
|
||||
return (*ke) != NULL;
|
||||
return (*ke) == NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2692,17 +3003,31 @@ return_bogus:
|
|||
static void
|
||||
process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
|
||||
struct sock_list* origin)
|
||||
struct sock_list* origin, int* suspend)
|
||||
{
|
||||
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
|
||||
struct key_entry_key* dske = NULL;
|
||||
uint8_t* olds = vq->empty_DS_name;
|
||||
int ret;
|
||||
*suspend = 0;
|
||||
vq->empty_DS_name = NULL;
|
||||
if(!ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske)) {
|
||||
ret = ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske);
|
||||
if(ret != 0) {
|
||||
switch(ret) {
|
||||
case 1:
|
||||
log_err("malloc failure in process_ds_response");
|
||||
vq->key_entry = NULL; /* make it error */
|
||||
vq->state = VAL_VALIDATE_STATE;
|
||||
return;
|
||||
case 2:
|
||||
*suspend = 1;
|
||||
return;
|
||||
default:
|
||||
log_err("unhandled error value for ds_response_to_ke");
|
||||
vq->key_entry = NULL; /* make it error */
|
||||
vq->state = VAL_VALIDATE_STATE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(dske == NULL) {
|
||||
vq->empty_DS_name = regional_alloc_init(qstate->region,
|
||||
|
@ -2954,9 +3279,26 @@ val_inform_super(struct module_qstate* qstate, int id,
|
|||
return;
|
||||
}
|
||||
if(qstate->qinfo.qtype == LDNS_RR_TYPE_DS) {
|
||||
int suspend;
|
||||
process_ds_response(super, vq, id, qstate->return_rcode,
|
||||
qstate->return_msg, &qstate->qinfo,
|
||||
qstate->reply_origin);
|
||||
qstate->reply_origin, &suspend);
|
||||
/* If NSEC3 was needed during validation, NULL the NSEC3 cache;
|
||||
* it will be re-initiated if needed later on.
|
||||
* Validation (and the cache table) are happening/allocated in
|
||||
* the super qstate whilst the RRs are allocated (and pointed
|
||||
* to) in this sub qstate. */
|
||||
if(vq->nsec3_cache_table.ct) {
|
||||
vq->nsec3_cache_table.ct = NULL;
|
||||
}
|
||||
if(suspend) {
|
||||
/* deep copy the return_msg to vq->sub_ds_msg; it will
|
||||
* be resumed later in the super state with the caveat
|
||||
* that the initial calculations will be re-caclulated
|
||||
* and re-suspended there before continuing. */
|
||||
vq->sub_ds_msg = dns_msg_deepcopy_region(
|
||||
qstate->return_msg, super->region);
|
||||
}
|
||||
return;
|
||||
} else if(qstate->qinfo.qtype == LDNS_RR_TYPE_DNSKEY) {
|
||||
process_dnskey_response(super, vq, id, qstate->return_rcode,
|
||||
|
@ -2970,8 +3312,15 @@ val_inform_super(struct module_qstate* qstate, int id,
|
|||
void
|
||||
val_clear(struct module_qstate* qstate, int id)
|
||||
{
|
||||
struct val_qstate* vq;
|
||||
if(!qstate)
|
||||
return;
|
||||
vq = (struct val_qstate*)qstate->minfo[id];
|
||||
if(vq) {
|
||||
if(vq->suspend_timer) {
|
||||
comm_timer_delete(vq->suspend_timer);
|
||||
}
|
||||
}
|
||||
/* everything is allocated in the region, so assign NULL */
|
||||
qstate->minfo[id] = NULL;
|
||||
}
|
||||
|
|
|
@ -45,11 +45,13 @@
|
|||
#include "util/module.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "validator/val_utils.h"
|
||||
#include "validator/val_nsec3.h"
|
||||
struct val_anchors;
|
||||
struct key_cache;
|
||||
struct key_entry_key;
|
||||
struct val_neg_cache;
|
||||
struct config_strlist;
|
||||
struct comm_timer;
|
||||
|
||||
/**
|
||||
* This is the TTL to use when a trust anchor fails to prime. A trust anchor
|
||||
|
@ -215,6 +217,19 @@ struct val_qstate {
|
|||
|
||||
/** true if this state is waiting to prime a trust anchor */
|
||||
int wait_prime_ta;
|
||||
|
||||
/** State to continue with RRSIG validation in a message later */
|
||||
int msg_signatures_state;
|
||||
/** The rrset index for the msg signatures to continue from */
|
||||
size_t msg_signatures_index;
|
||||
/** Cache table for NSEC3 hashes */
|
||||
struct nsec3_cache_table nsec3_cache_table;
|
||||
/** DS message from sub if it got suspended from NSEC3 calculations */
|
||||
struct dns_msg* sub_ds_msg;
|
||||
/** The timer to resume processing msg signatures */
|
||||
struct comm_timer* suspend_timer;
|
||||
/** Number of suspends */
|
||||
int suspend_count;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -262,4 +277,7 @@ void val_clear(struct module_qstate* qstate, int id);
|
|||
*/
|
||||
size_t val_get_mem(struct module_env* env, int id);
|
||||
|
||||
/** Timer callback for msg signatures continue timer */
|
||||
void validate_suspend_timer_cb(void* arg);
|
||||
|
||||
#endif /* VALIDATOR_VALIDATOR_H */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: mvacc.c,v 1.5 2022/07/11 10:44:08 jmatthew Exp $ */
|
||||
/* $OpenBSD: mvacc.c,v 1.6 2024/02/13 02:14:25 jsg Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2016 Patrick Wildt <patrick@blueri.se>
|
||||
*
|
||||
|
@ -133,7 +133,7 @@ mvacc_get_frequency(void *cookie, uint32_t *cells)
|
|||
cpu = (sar >> SAR_CPU_DDR_FREQ_OPT) & SAR_CPU_DDR_FREQ_OPT_MASK;
|
||||
tclk = (sar >> SAR_TCLK_FREQ_OPT) & SAR_TCLK_FREQ_OPT_MASK;
|
||||
|
||||
if (cpu > nitems(mvacc_cpu_freqs)) {
|
||||
if (cpu >= nitems(mvacc_cpu_freqs)) {
|
||||
printf("%s: invalid cpu frequency", sc->sc_dev.dv_xname);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ehci_fdt.c,v 1.11 2024/01/26 17:11:50 kettenis Exp $ */
|
||||
/* $OpenBSD: ehci_fdt.c,v 1.12 2024/02/12 21:37:25 uaa Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
|
||||
|
@ -207,6 +207,7 @@ struct ehci_phy ehci_phys[] = {
|
|||
{ "allwinner,sun8i-v3s-usb-phy", sun4i_phy_init },
|
||||
{ "allwinner,sun20i-d1-usb-phy", sun4i_phy_init },
|
||||
{ "allwinner,sun50i-h6-usb-phy", sun4i_phy_init },
|
||||
{ "allwinner,sun50i-h616-usb-phy", sun4i_phy_init },
|
||||
{ "allwinner,sun50i-a64-usb-phy", sun4i_phy_init },
|
||||
{ "allwinner,sun9i-a80-usb-phy", sun9i_phy_init },
|
||||
};
|
||||
|
@ -286,6 +287,62 @@ ehci_init_phys(struct ehci_fdt_softc *sc)
|
|||
#define SUNXI_AHB_INCR8 (1 << 10)
|
||||
#define SUNXI_AHB_INCR16 (1 << 11)
|
||||
|
||||
void
|
||||
sun50i_h616_phy2_init(struct ehci_fdt_softc *sc, int node)
|
||||
{
|
||||
int len, idx;
|
||||
uint32_t *reg, val;
|
||||
bus_size_t size;
|
||||
bus_space_handle_t ioh;
|
||||
|
||||
/*
|
||||
* to access USB2-PHY register, get address from "reg" property of
|
||||
* current "allwinner,...-usb-phy" node
|
||||
*/
|
||||
len = OF_getproplen(node, "reg");
|
||||
if (len <= 0)
|
||||
goto out;
|
||||
|
||||
reg = malloc(len, M_TEMP, M_WAITOK);
|
||||
OF_getpropintarray(node, "reg", reg, len);
|
||||
|
||||
idx = OF_getindex(node, "pmu2", "reg-names");
|
||||
if (idx < 0 || (idx + 1) > (len / (sizeof(uint32_t) * 2))) {
|
||||
printf(": no phy2 register\n");
|
||||
goto free;
|
||||
}
|
||||
|
||||
/* convert "reg-names" index to "reg" (address-size pair) index */
|
||||
idx *= 2;
|
||||
|
||||
size = reg[idx + 1];
|
||||
if (bus_space_map(sc->sc.iot, reg[idx], size, 0, &ioh)) {
|
||||
printf(": can't map phy2 registers\n");
|
||||
goto free;
|
||||
}
|
||||
|
||||
clock_enable(node, "usb2_phy");
|
||||
reset_deassert(node, "usb2_reset");
|
||||
clock_enable(node, "pmu2_clk");
|
||||
|
||||
/*
|
||||
* address is offset from "pmu2", not EHCI2 base address
|
||||
* (normally it points EHCI2 base address + 0x810)
|
||||
*/
|
||||
val = bus_space_read_4(sc->sc.iot, ioh, 0x10);
|
||||
val &= ~(1 << 3); /* clear SIDDQ */
|
||||
bus_space_write_4(sc->sc.iot, ioh, 0x10, val);
|
||||
|
||||
clock_disable(node, "pmu2_clk");
|
||||
/* "usb2_reset" and "usb2_phy" unchanged */
|
||||
|
||||
bus_space_unmap(sc->sc.iot, ioh, size);
|
||||
free:
|
||||
free(reg, M_TEMP, len);
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
sun4i_phy_init(struct ehci_fdt_softc *sc, uint32_t *cells)
|
||||
{
|
||||
|
@ -298,6 +355,11 @@ sun4i_phy_init(struct ehci_fdt_softc *sc, uint32_t *cells)
|
|||
if (node == -1)
|
||||
return;
|
||||
|
||||
/* Allwinner H616 needs to clear PHY2's SIDDQ flag */
|
||||
if (OF_is_compatible(node, "allwinner,sun50i-h616-usb-phy") &&
|
||||
cells[1] != 2)
|
||||
sun50i_h616_phy2_init(sc, node);
|
||||
|
||||
val = bus_space_read_4(sc->sc.iot, sc->sc.ioh, SUNXI_HCI_ICR);
|
||||
val |= SUNXI_AHB_INCR8 | SUNXI_AHB_INCR4;
|
||||
val |= SUNXI_AHB_INCRX_ALIGN;
|
||||
|
@ -315,11 +377,19 @@ sun4i_phy_init(struct ehci_fdt_softc *sc, uint32_t *cells)
|
|||
val = bus_space_read_4(sc->sc.iot, sc->sc.ioh, 0x810);
|
||||
val &= ~(1 << 1);
|
||||
bus_space_write_4(sc->sc.iot, sc->sc.ioh, 0x810, val);
|
||||
} else if (OF_is_compatible(node, "allwinner,sun20i-d1-usb-phy")) {
|
||||
} else if (OF_is_compatible(node, "allwinner,sun8i-a83t-usb-phy") ||
|
||||
OF_is_compatible(node, "allwinner,sun20i-d1-usb-phy") ||
|
||||
OF_is_compatible(node, "allwinner,sun50i-h616-usb-phy")) {
|
||||
val = bus_space_read_4(sc->sc.iot, sc->sc.ioh, 0x810);
|
||||
val &= ~(1 << 3);
|
||||
bus_space_write_4(sc->sc.iot, sc->sc.ioh, 0x810, val);
|
||||
}
|
||||
if (OF_is_compatible(node, "allwinner,sun8i-a83t-usb-phy") ||
|
||||
OF_is_compatible(node, "allwinner,sun50i-h616-usb-phy")) {
|
||||
val = bus_space_read_4(sc->sc.iot, sc->sc.ioh, 0x810);
|
||||
val |= 1 << 5;
|
||||
bus_space_write_4(sc->sc.iot, sc->sc.ioh, 0x810, val);
|
||||
}
|
||||
|
||||
pinctrl_byname(node, "default");
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: if_bnxt.c,v 1.45 2024/01/19 03:25:13 jmatthew Exp $ */
|
||||
/* $OpenBSD: if_bnxt.c,v 1.46 2024/02/13 13:58:19 bluhm Exp $ */
|
||||
/*-
|
||||
* Broadcom NetXtreme-C/E network driver.
|
||||
*
|
||||
|
@ -1433,13 +1433,13 @@ bnxt_start(struct ifqueue *ifq)
|
|||
lflags |= TX_BD_LONG_LFLAGS_LSO;
|
||||
hdrsize = sizeof(*ext.eh);
|
||||
if (ext.ip4)
|
||||
hdrsize += ext.ip4->ip_hl << 2;
|
||||
hdrsize += ext.ip4hlen;
|
||||
else if (ext.ip6)
|
||||
hdrsize += sizeof(*ext.ip6);
|
||||
else
|
||||
tcpstat_inc(tcps_outbadtso);
|
||||
|
||||
hdrsize += ext.tcp->th_off << 2;
|
||||
hdrsize += ext.tcphlen;
|
||||
txhi->hdr_size = htole16(hdrsize / 2);
|
||||
|
||||
outlen = m->m_pkthdr.ph_mss;
|
||||
|
|
|
@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
***************************************************************************/
|
||||
|
||||
/* $OpenBSD: if_em.c,v 1.371 2024/01/28 18:42:58 mglocker Exp $ */
|
||||
/* $OpenBSD: if_em.c,v 1.372 2024/02/13 13:58:19 bluhm Exp $ */
|
||||
/* $FreeBSD: if_em.c,v 1.46 2004/09/29 18:28:28 mlaier Exp $ */
|
||||
|
||||
#include <dev/pci/if_em.h>
|
||||
|
@ -2433,7 +2433,7 @@ em_tx_ctx_setup(struct em_queue *que, struct mbuf *mp, u_int head,
|
|||
vlan_macip_lens |= (sizeof(*ext.eh) << E1000_ADVTXD_MACLEN_SHIFT);
|
||||
|
||||
if (ext.ip4) {
|
||||
iphlen = ext.ip4->ip_hl << 2;
|
||||
iphlen = ext.ip4hlen;
|
||||
|
||||
type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_IPV4;
|
||||
if (ISSET(mp->m_pkthdr.csum_flags, M_IPV4_CSUM_OUT)) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: if_igc.c,v 1.15 2024/01/23 08:48:12 kevlo Exp $ */
|
||||
/* $OpenBSD: if_igc.c,v 1.16 2024/02/13 13:58:19 bluhm Exp $ */
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
|
@ -2028,7 +2028,7 @@ igc_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp, int prod,
|
|||
ether_extract_headers(mp, &ext);
|
||||
|
||||
if (ext.ip4) {
|
||||
iphlen = ext.ip4->ip_hl << 2;
|
||||
iphlen = ext.ip4hlen;
|
||||
|
||||
type_tucmd_mlhl |= IGC_ADVTXD_TUCMD_IPV4;
|
||||
if (ISSET(mp->m_pkthdr.csum_flags, M_IPV4_CSUM_OUT)) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: if_ix.c,v 1.206 2023/11/10 15:51:20 bluhm Exp $ */
|
||||
/* $OpenBSD: if_ix.c,v 1.207 2024/02/13 13:58:19 bluhm Exp $ */
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
|
@ -2502,7 +2502,7 @@ ixgbe_tx_offload(struct mbuf *mp, uint32_t *vlan_macip_lens,
|
|||
*vlan_macip_lens |= (ethlen << IXGBE_ADVTXD_MACLEN_SHIFT);
|
||||
|
||||
if (ext.ip4) {
|
||||
iphlen = ext.ip4->ip_hl << 2;
|
||||
iphlen = ext.ip4hlen;
|
||||
|
||||
if (ISSET(mp->m_pkthdr.csum_flags, M_IPV4_CSUM_OUT)) {
|
||||
*olinfo_status |= IXGBE_TXD_POPTS_IXSM << 8;
|
||||
|
@ -2542,7 +2542,7 @@ ixgbe_tx_offload(struct mbuf *mp, uint32_t *vlan_macip_lens,
|
|||
if (ext.tcp) {
|
||||
uint32_t hdrlen, thlen, paylen, outlen;
|
||||
|
||||
thlen = ext.tcp->th_off << 2;
|
||||
thlen = ext.tcphlen;
|
||||
|
||||
outlen = mp->m_pkthdr.ph_mss;
|
||||
*mss_l4len_idx |= outlen << IXGBE_ADVTXD_MSS_SHIFT;
|
||||
|
@ -3277,11 +3277,11 @@ ixgbe_rxeof(struct rx_ring *rxr)
|
|||
hdrlen += ETHER_VLAN_ENCAP_LEN;
|
||||
#endif
|
||||
if (ext.ip4)
|
||||
hdrlen += ext.ip4->ip_hl << 2;
|
||||
hdrlen += ext.ip4hlen;
|
||||
if (ext.ip6)
|
||||
hdrlen += sizeof(*ext.ip6);
|
||||
if (ext.tcp) {
|
||||
hdrlen += ext.tcp->th_off << 2;
|
||||
hdrlen += ext.tcphlen;
|
||||
tcpstat_inc(tcps_inhwlro);
|
||||
tcpstat_add(tcps_inpktlro, pkts);
|
||||
} else {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: if_vio.c,v 1.29 2023/12/20 09:51:06 jan Exp $ */
|
||||
/* $OpenBSD: if_vio.c,v 1.30 2024/02/13 13:58:19 bluhm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Stefan Fritsch, Alexander Fiveg.
|
||||
|
@ -765,7 +765,7 @@ again:
|
|||
hdr->csum_offset = offsetof(struct udphdr, uh_sum);
|
||||
|
||||
if (ext.ip4)
|
||||
hdr->csum_start += ext.ip4->ip_hl << 2;
|
||||
hdr->csum_start += ext.ip4hlen;
|
||||
#ifdef INET6
|
||||
else if (ext.ip6)
|
||||
hdr->csum_start += sizeof(*ext.ip6);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: kern_clock.c,v 1.122 2024/02/09 17:42:18 cheloha Exp $ */
|
||||
/* $OpenBSD: kern_clock.c,v 1.123 2024/02/12 22:07:33 cheloha Exp $ */
|
||||
/* $NetBSD: kern_clock.c,v 1.34 1996/06/09 04:51:03 briggs Exp $ */
|
||||
|
||||
/*-
|
||||
|
@ -140,13 +140,6 @@ initclocks(void)
|
|||
void
|
||||
hardclock(struct clockframe *frame)
|
||||
{
|
||||
/*
|
||||
* If we are not the primary CPU, we're not allowed to do
|
||||
* any more work.
|
||||
*/
|
||||
if (CPU_IS_PRIMARY(curcpu()) == 0)
|
||||
return;
|
||||
|
||||
tc_ticktock();
|
||||
ticks++;
|
||||
jiffies++;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: kern_clockintr.c,v 1.66 2024/02/09 16:52:58 cheloha Exp $ */
|
||||
/* $OpenBSD: kern_clockintr.c,v 1.67 2024/02/12 22:07:33 cheloha Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2003 Dale Rahn <drahn@openbsd.org>
|
||||
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
|
||||
|
@ -63,7 +63,7 @@ clockintr_cpu_init(const struct intrclock *ic)
|
|||
clockqueue_intrclock_install(cq, ic);
|
||||
|
||||
/* TODO: Remove this from struct clockintr_queue. */
|
||||
if (cq->cq_hardclock.cl_expiration == 0) {
|
||||
if (CPU_IS_PRIMARY(ci) && cq->cq_hardclock.cl_expiration == 0) {
|
||||
clockintr_bind(&cq->cq_hardclock, ci, clockintr_hardclock,
|
||||
NULL);
|
||||
}
|
||||
|
@ -99,12 +99,6 @@ clockintr_cpu_init(const struct intrclock *ic)
|
|||
clockintr_schedule(&cq->cq_hardclock, 0);
|
||||
else
|
||||
clockintr_advance(&cq->cq_hardclock, hardclock_period);
|
||||
} else {
|
||||
if (cq->cq_hardclock.cl_expiration == 0) {
|
||||
clockintr_stagger(&cq->cq_hardclock, hardclock_period,
|
||||
multiplier, MAXCPUS);
|
||||
}
|
||||
clockintr_advance(&cq->cq_hardclock, hardclock_period);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: uipc_socket.c,v 1.319 2024/02/11 21:36:49 mvs Exp $ */
|
||||
/* $OpenBSD: uipc_socket.c,v 1.320 2024/02/12 22:48:27 mvs Exp $ */
|
||||
/* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -132,8 +132,9 @@ soinit(void)
|
|||
}
|
||||
|
||||
struct socket *
|
||||
soalloc(const struct domain *dp, int wait)
|
||||
soalloc(const struct protosw *prp, int wait)
|
||||
{
|
||||
const struct domain *dp = prp->pr_domain;
|
||||
struct socket *so;
|
||||
|
||||
so = pool_get(&socket_pool, (wait == M_WAIT ? PR_WAITOK : PR_NOWAIT) |
|
||||
|
@ -153,7 +154,7 @@ soalloc(const struct domain *dp, int wait)
|
|||
switch (dp->dom_family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
switch (dp->dom_protosw->pr_type) {
|
||||
switch (prp->pr_type) {
|
||||
case SOCK_DGRAM:
|
||||
case SOCK_RAW:
|
||||
so->so_rcv.sb_flags |= SB_MTXLOCK;
|
||||
|
@ -188,7 +189,7 @@ socreate(int dom, struct socket **aso, int type, int proto)
|
|||
return (EPROTONOSUPPORT);
|
||||
if (prp->pr_type != type)
|
||||
return (EPROTOTYPE);
|
||||
so = soalloc(pffinddomain(dom), M_WAIT);
|
||||
so = soalloc(prp, M_WAIT);
|
||||
so->so_type = type;
|
||||
if (suser(p) == 0)
|
||||
so->so_state = SS_PRIV;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: uipc_socket2.c,v 1.143 2024/02/11 18:14:26 mvs Exp $ */
|
||||
/* $OpenBSD: uipc_socket2.c,v 1.144 2024/02/12 22:48:27 mvs Exp $ */
|
||||
/* $NetBSD: uipc_socket2.c,v 1.11 1996/02/04 02:17:55 christos Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -188,7 +188,7 @@ sonewconn(struct socket *head, int connstatus, int wait)
|
|||
return (NULL);
|
||||
if (head->so_qlen + head->so_q0len > head->so_qlimit * 3)
|
||||
return (NULL);
|
||||
so = soalloc(head->so_proto->pr_domain, wait);
|
||||
so = soalloc(head->so_proto, wait);
|
||||
if (so == NULL)
|
||||
return (NULL);
|
||||
so->so_type = head->so_type;
|
||||
|
|
|
@ -513,12 +513,12 @@ typedef uLong FAR uLongf;
|
|||
|
||||
#if !defined(_WIN32) && defined(Z_LARGE64)
|
||||
# define z_off64_t off64_t
|
||||
#elif defined(_WIN32) && !defined(__GNUC__)
|
||||
# define z_off64_t __int64
|
||||
#elif defined(__GO32__)
|
||||
# define z_off64_t offset_t
|
||||
#else
|
||||
# if defined(_WIN32) && !defined(__GNUC__)
|
||||
# define z_off64_t __int64
|
||||
# else
|
||||
# define z_off64_t z_off_t
|
||||
# endif
|
||||
# define z_off64_t z_off_t
|
||||
#endif
|
||||
|
||||
/* MVS linker does not support external names larger than 8 bytes */
|
||||
|
|
|
@ -1891,9 +1891,9 @@ ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */
|
|||
ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int);
|
||||
ZEXTERN z_off_t ZEXPORT gztell64(gzFile);
|
||||
ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile);
|
||||
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);
|
||||
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t);
|
||||
# endif
|
||||
#else
|
||||
ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *);
|
||||
|
|
|
@ -184,11 +184,10 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
|
|||
#endif
|
||||
|
||||
/* provide prototypes for these when building zlib without LFS */
|
||||
#if !defined(_WIN32) && \
|
||||
(!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
|
||||
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);
|
||||
#ifndef Z_LARGE64
|
||||
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t);
|
||||
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t);
|
||||
#endif
|
||||
|
||||
/* common defaults */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: if_bridge.c,v 1.368 2023/05/16 14:32:54 jan Exp $ */
|
||||
/* $OpenBSD: if_bridge.c,v 1.369 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
|
||||
|
@ -48,6 +48,7 @@
|
|||
#include <net/if_types.h>
|
||||
#include <net/if_llc.h>
|
||||
#include <net/netisr.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: if_etherip.c,v 1.54 2023/12/23 10:52:54 bluhm Exp $ */
|
||||
/* $OpenBSD: if_etherip.c,v 1.55 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2015 Kazuya GODA <goda@openbsd.org>
|
||||
*
|
||||
|
@ -31,6 +31,7 @@
|
|||
#include <net/if_var.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net/route.h>
|
||||
#include <net/rtable.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: if_ethersubr.c,v 1.291 2023/07/27 20:21:25 jan Exp $ */
|
||||
/* $OpenBSD: if_ethersubr.c,v 1.292 2024/02/13 13:58:19 bluhm Exp $ */
|
||||
/* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -140,6 +140,20 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
|
|||
#include <netmpls/mpls.h>
|
||||
#endif /* MPLS */
|
||||
|
||||
/* #define ETHERDEBUG 1 */
|
||||
#ifdef ETHERDEBUG
|
||||
int etherdebug = ETHERDEBUG;
|
||||
#define DNPRINTF(level, fmt, args...) \
|
||||
do { \
|
||||
if (etherdebug >= level) \
|
||||
printf("%s: " fmt "\n", __func__, ## args); \
|
||||
} while (0)
|
||||
#else
|
||||
#define DNPRINTF(level, fmt, args...) \
|
||||
do { } while (0)
|
||||
#endif
|
||||
#define DPRINTF(fmt, args...) DNPRINTF(1, fmt, args)
|
||||
|
||||
u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN] =
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
u_int8_t etheranyaddr[ETHER_ADDR_LEN] =
|
||||
|
@ -1034,56 +1048,126 @@ ether_e64_to_addr(struct ether_addr *ea, uint64_t e64)
|
|||
|
||||
/* Parse different TCP/IP protocol headers for a quick view inside an mbuf. */
|
||||
void
|
||||
ether_extract_headers(struct mbuf *mp, struct ether_extracted *ext)
|
||||
ether_extract_headers(struct mbuf *m0, struct ether_extracted *ext)
|
||||
{
|
||||
struct mbuf *m;
|
||||
uint64_t hlen;
|
||||
size_t hlen;
|
||||
int hoff;
|
||||
uint8_t ipproto;
|
||||
uint16_t ether_type;
|
||||
/* gcc 4.2.1 on sparc64 may create 32 bit loads on unaligned mbuf */
|
||||
union {
|
||||
u_char hc_data;
|
||||
#if _BYTE_ORDER == _LITTLE_ENDIAN
|
||||
struct {
|
||||
u_int hl:4, /* header length */
|
||||
v:4; /* version */
|
||||
} hc_ip;
|
||||
struct {
|
||||
u_int x2:4, /* (unused) */
|
||||
off:4; /* data offset */
|
||||
} hc_th;
|
||||
#endif
|
||||
#if _BYTE_ORDER == _BIG_ENDIAN
|
||||
struct {
|
||||
u_int v:4, /* version */
|
||||
hl:4; /* header length */
|
||||
} hc_ip;
|
||||
struct {
|
||||
u_int off:4, /* data offset */
|
||||
x2:4; /* (unused) */
|
||||
} hc_th;
|
||||
#endif
|
||||
} hdrcpy;
|
||||
|
||||
/* Return NULL if header was not recognized. */
|
||||
memset(ext, 0, sizeof(*ext));
|
||||
|
||||
if (mp->m_len < sizeof(*ext->eh))
|
||||
return;
|
||||
KASSERT(ISSET(m0->m_flags, M_PKTHDR));
|
||||
ext->paylen = m0->m_pkthdr.len;
|
||||
|
||||
ext->eh = mtod(mp, struct ether_header *);
|
||||
if (m0->m_len < sizeof(*ext->eh)) {
|
||||
DPRINTF("m_len %d, eh %zu", m0->m_len, sizeof(*ext->eh));
|
||||
return;
|
||||
}
|
||||
ext->eh = mtod(m0, struct ether_header *);
|
||||
ether_type = ntohs(ext->eh->ether_type);
|
||||
hlen = sizeof(*ext->eh);
|
||||
if (ext->paylen < hlen) {
|
||||
DPRINTF("paylen %u, ehlen %zu", ext->paylen, hlen);
|
||||
ext->eh = NULL;
|
||||
return;
|
||||
}
|
||||
ext->paylen -= hlen;
|
||||
|
||||
#if NVLAN > 0
|
||||
if (ether_type == ETHERTYPE_VLAN) {
|
||||
ext->evh = mtod(mp, struct ether_vlan_header *);
|
||||
if (m0->m_len < sizeof(*ext->evh)) {
|
||||
DPRINTF("m_len %d, evh %zu",
|
||||
m0->m_len, sizeof(*ext->evh));
|
||||
return;
|
||||
}
|
||||
ext->evh = mtod(m0, struct ether_vlan_header *);
|
||||
ether_type = ntohs(ext->evh->evl_proto);
|
||||
hlen = sizeof(*ext->evh);
|
||||
if (sizeof(*ext->eh) + ext->paylen < hlen) {
|
||||
DPRINTF("paylen %zu, evhlen %zu",
|
||||
sizeof(*ext->eh) + ext->paylen, hlen);
|
||||
ext->evh = NULL;
|
||||
return;
|
||||
}
|
||||
ext->paylen = sizeof(*ext->eh) + ext->paylen - hlen;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (ether_type) {
|
||||
case ETHERTYPE_IP:
|
||||
m = m_getptr(mp, hlen, &hoff);
|
||||
if (m == NULL || m->m_len - hoff < sizeof(*ext->ip4))
|
||||
m = m_getptr(m0, hlen, &hoff);
|
||||
if (m == NULL || m->m_len - hoff < sizeof(*ext->ip4)) {
|
||||
DPRINTF("m_len %d, hoff %d, ip4 %zu",
|
||||
m ? m->m_len : -1, hoff, sizeof(*ext->ip4));
|
||||
return;
|
||||
}
|
||||
ext->ip4 = (struct ip *)(mtod(m, caddr_t) + hoff);
|
||||
|
||||
memcpy(&hdrcpy.hc_data, ext->ip4, 1);
|
||||
hlen = hdrcpy.hc_ip.hl << 2;
|
||||
if (m->m_len - hoff < hlen) {
|
||||
DPRINTF("m_len %d, hoff %d, iphl %zu",
|
||||
m ? m->m_len : -1, hoff, hlen);
|
||||
ext->ip4 = NULL;
|
||||
return;
|
||||
}
|
||||
if (ext->paylen < hlen) {
|
||||
DPRINTF("paylen %u, ip4hlen %zu", ext->paylen, hlen);
|
||||
ext->ip4 = NULL;
|
||||
return;
|
||||
}
|
||||
ext->ip4hlen = hlen;
|
||||
ext->paylen -= hlen;
|
||||
ipproto = ext->ip4->ip_p;
|
||||
|
||||
if (ISSET(ntohs(ext->ip4->ip_off), IP_MF|IP_OFFMASK))
|
||||
return;
|
||||
|
||||
hlen = ext->ip4->ip_hl << 2;
|
||||
ipproto = ext->ip4->ip_p;
|
||||
|
||||
break;
|
||||
#ifdef INET6
|
||||
case ETHERTYPE_IPV6:
|
||||
m = m_getptr(mp, hlen, &hoff);
|
||||
if (m == NULL || m->m_len - hoff < sizeof(*ext->ip6))
|
||||
m = m_getptr(m0, hlen, &hoff);
|
||||
if (m == NULL || m->m_len - hoff < sizeof(*ext->ip6)) {
|
||||
DPRINTF("m_len %d, hoff %d, ip6 %zu",
|
||||
m ? m->m_len : -1, hoff, sizeof(*ext->ip6));
|
||||
return;
|
||||
}
|
||||
ext->ip6 = (struct ip6_hdr *)(mtod(m, caddr_t) + hoff);
|
||||
|
||||
hlen = sizeof(*ext->ip6);
|
||||
if (ext->paylen < hlen) {
|
||||
DPRINTF("paylen %u, ip6hlen %zu", ext->paylen, hlen);
|
||||
ext->ip6 = NULL;
|
||||
return;
|
||||
}
|
||||
ext->paylen -= hlen;
|
||||
ipproto = ext->ip6->ip6_nxt;
|
||||
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
@ -1093,16 +1177,51 @@ ether_extract_headers(struct mbuf *mp, struct ether_extracted *ext)
|
|||
switch (ipproto) {
|
||||
case IPPROTO_TCP:
|
||||
m = m_getptr(m, hoff + hlen, &hoff);
|
||||
if (m == NULL || m->m_len - hoff < sizeof(*ext->tcp))
|
||||
if (m == NULL || m->m_len - hoff < sizeof(*ext->tcp)) {
|
||||
DPRINTF("m_len %d, hoff %d, tcp %zu",
|
||||
m ? m->m_len : -1, hoff, sizeof(*ext->tcp));
|
||||
return;
|
||||
}
|
||||
ext->tcp = (struct tcphdr *)(mtod(m, caddr_t) + hoff);
|
||||
|
||||
memcpy(&hdrcpy.hc_data, &ext->tcp->th_flags - 1, 1);
|
||||
hlen = hdrcpy.hc_th.off << 2;
|
||||
if (m->m_len - hoff < hlen) {
|
||||
DPRINTF("m_len %d, hoff %d, thoff %zu",
|
||||
m ? m->m_len : -1, hoff, hlen);
|
||||
ext->tcp = NULL;
|
||||
return;
|
||||
}
|
||||
if (ext->paylen < hlen) {
|
||||
DPRINTF("paylen %u, tcphlen %zu", ext->paylen, hlen);
|
||||
ext->tcp = NULL;
|
||||
return;
|
||||
}
|
||||
ext->tcphlen = hlen;
|
||||
ext->paylen -= hlen;
|
||||
break;
|
||||
|
||||
case IPPROTO_UDP:
|
||||
m = m_getptr(m, hoff + hlen, &hoff);
|
||||
if (m == NULL || m->m_len - hoff < sizeof(*ext->udp))
|
||||
if (m == NULL || m->m_len - hoff < sizeof(*ext->udp)) {
|
||||
DPRINTF("m_len %d, hoff %d, tcp %zu",
|
||||
m ? m->m_len : -1, hoff, sizeof(*ext->tcp));
|
||||
return;
|
||||
}
|
||||
ext->udp = (struct udphdr *)(mtod(m, caddr_t) + hoff);
|
||||
|
||||
hlen = sizeof(*ext->udp);
|
||||
if (ext->paylen < hlen) {
|
||||
DPRINTF("paylen %u, udphlen %zu", ext->paylen, hlen);
|
||||
ext->udp = NULL;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
DNPRINTF(2, "%s%s%s%s%s%s ip4h %u, tcph %u, payl %u",
|
||||
ext->eh ? "eh," : "", ext->evh ? "evh," : "",
|
||||
ext->ip4 ? "ip4," : "", ext->ip6 ? "ip6," : "",
|
||||
ext->tcp ? "tcp," : "", ext->udp ? "udp," : "",
|
||||
ext->ip4hlen, ext->tcphlen, ext->paylen);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: if_pfsync.c,v 1.324 2023/12/23 10:52:54 bluhm Exp $ */
|
||||
/* $OpenBSD: if_pfsync.c,v 1.325 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 Michael Shalayeff
|
||||
|
@ -69,6 +69,7 @@
|
|||
#include <net/if_types.h>
|
||||
#include <net/bpf.h>
|
||||
#include <net/netisr.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: if_veb.c,v 1.34 2023/12/23 10:52:54 bluhm Exp $ */
|
||||
/* $OpenBSD: if_veb.c,v 1.35 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021 David Gwynne <dlg@openbsd.org>
|
||||
|
@ -46,7 +46,6 @@
|
|||
#ifdef INET6
|
||||
#include <netinet6/in6_var.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
#endif
|
||||
|
||||
#if 0 && defined(IPSEC)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: route.c,v 1.431 2024/02/09 14:02:11 bluhm Exp $ */
|
||||
/* $OpenBSD: route.c,v 1.432 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -212,8 +212,8 @@ route_cache(struct route *ro, struct in_addr addr, u_int rtableid)
|
|||
if (rtisvalid(ro->ro_rt) &&
|
||||
ro->ro_generation == gen &&
|
||||
ro->ro_tableid == rtableid &&
|
||||
ro->ro_dst.sa_family == AF_INET &&
|
||||
satosin(&ro->ro_dst)->sin_addr.s_addr == addr.s_addr) {
|
||||
ro->ro_dstsa.sa_family == AF_INET &&
|
||||
ro->ro_dstsin.sin_addr.s_addr == addr.s_addr) {
|
||||
ipstat_inc(ips_rtcachehit);
|
||||
return (0);
|
||||
}
|
||||
|
@ -225,17 +225,16 @@ route_cache(struct route *ro, struct in_addr addr, u_int rtableid)
|
|||
ro->ro_tableid = rtableid;
|
||||
|
||||
memset(&ro->ro_dst, 0, sizeof(ro->ro_dst));
|
||||
satosin(&ro->ro_dst)->sin_family = AF_INET;
|
||||
satosin(&ro->ro_dst)->sin_len = sizeof(struct sockaddr_in);
|
||||
satosin(&ro->ro_dst)->sin_addr = addr;
|
||||
ro->ro_dstsin.sin_family = AF_INET;
|
||||
ro->ro_dstsin.sin_len = sizeof(struct sockaddr_in);
|
||||
ro->ro_dstsin.sin_addr = addr;
|
||||
|
||||
return (ESRCH);
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
int
|
||||
route6_cache(struct route_in6 *ro, const struct in6_addr *addr,
|
||||
u_int rtableid)
|
||||
route6_cache(struct route *ro, const struct in6_addr *addr, u_int rtableid)
|
||||
{
|
||||
u_long gen;
|
||||
|
||||
|
@ -245,8 +244,8 @@ route6_cache(struct route_in6 *ro, const struct in6_addr *addr,
|
|||
if (rtisvalid(ro->ro_rt) &&
|
||||
ro->ro_generation == gen &&
|
||||
ro->ro_tableid == rtableid &&
|
||||
ro->ro_dst.sin6_family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, addr)) {
|
||||
ro->ro_dstsa.sa_family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&ro->ro_dstsin6.sin6_addr, addr)) {
|
||||
ip6stat_inc(ip6s_rtcachehit);
|
||||
return (0);
|
||||
}
|
||||
|
@ -258,9 +257,9 @@ route6_cache(struct route_in6 *ro, const struct in6_addr *addr,
|
|||
ro->ro_tableid = rtableid;
|
||||
|
||||
memset(&ro->ro_dst, 0, sizeof(ro->ro_dst));
|
||||
ro->ro_dst.sin6_family = AF_INET6;
|
||||
ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6);
|
||||
ro->ro_dst.sin6_addr = *addr;
|
||||
ro->ro_dstsin6.sin6_family = AF_INET6;
|
||||
ro->ro_dstsin6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
ro->ro_dstsin6.sin6_addr = *addr;
|
||||
|
||||
return (ESRCH);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: route.h,v 1.205 2024/02/05 12:52:11 aoyama Exp $ */
|
||||
/* $OpenBSD: route.h,v 1.206 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $NetBSD: route.h,v 1.9 1996/02/13 22:00:49 christos Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -370,6 +370,19 @@ struct sockaddr_rtsearch {
|
|||
char sr_search[RTSEARCH_LEN];
|
||||
};
|
||||
|
||||
struct rt_addrinfo {
|
||||
int rti_addrs;
|
||||
const struct sockaddr *rti_info[RTAX_MAX];
|
||||
int rti_flags;
|
||||
struct ifaddr *rti_ifa;
|
||||
struct rt_msghdr *rti_rtm;
|
||||
u_char rti_mpls;
|
||||
};
|
||||
|
||||
#ifdef __BSD_VISIBLE
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
/*
|
||||
* A route consists of a destination address and a reference
|
||||
* to a routing entry. These are often held by protocols
|
||||
|
@ -379,17 +392,17 @@ struct route {
|
|||
struct rtentry *ro_rt;
|
||||
u_long ro_generation;
|
||||
u_long ro_tableid; /* u_long because of alignment */
|
||||
struct sockaddr ro_dst;
|
||||
union {
|
||||
struct sockaddr rod_sa;
|
||||
struct sockaddr_in rod_sin;
|
||||
struct sockaddr_in6 rod_sin6;
|
||||
} ro_dst;
|
||||
#define ro_dstsa ro_dst.rod_sa
|
||||
#define ro_dstsin ro_dst.rod_sin
|
||||
#define ro_dstsin6 ro_dst.rod_sin6
|
||||
};
|
||||
|
||||
struct rt_addrinfo {
|
||||
int rti_addrs;
|
||||
const struct sockaddr *rti_info[RTAX_MAX];
|
||||
int rti_flags;
|
||||
struct ifaddr *rti_ifa;
|
||||
struct rt_msghdr *rti_rtm;
|
||||
u_char rti_mpls;
|
||||
};
|
||||
#endif /* __BSD_VISIBLE */
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
|
@ -449,6 +462,8 @@ struct if_ieee80211_data;
|
|||
struct bfd_config;
|
||||
|
||||
void route_init(void);
|
||||
int route_cache(struct route *, struct in_addr, u_int);
|
||||
int route6_cache(struct route *, const struct in6_addr *, u_int);
|
||||
void rtm_ifchg(struct ifnet *);
|
||||
void rtm_ifannounce(struct ifnet *, int);
|
||||
void rtm_bfd(struct bfd_config *);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: if_ether.h,v 1.90 2023/07/27 20:21:25 jan Exp $ */
|
||||
/* $OpenBSD: if_ether.h,v 1.91 2024/02/13 13:58:19 bluhm Exp $ */
|
||||
/* $NetBSD: if_ether.h,v 1.22 1996/05/11 13:00:00 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -307,6 +307,9 @@ struct ether_extracted {
|
|||
struct ip6_hdr *ip6;
|
||||
struct tcphdr *tcp;
|
||||
struct udphdr *udp;
|
||||
u_int ip4hlen;
|
||||
u_int tcphlen;
|
||||
u_int paylen;
|
||||
};
|
||||
|
||||
void ether_extract_headers(struct mbuf *, struct ether_extracted *);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: in.h,v 1.147 2024/02/09 14:02:11 bluhm Exp $ */
|
||||
/* $OpenBSD: in.h,v 1.148 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $NetBSD: in.h,v 1.20 1996/02/13 23:41:47 christos Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -789,8 +789,6 @@ void in_len2mask(struct in_addr *, int);
|
|||
int in_nam2sin(const struct mbuf *, struct sockaddr_in **);
|
||||
int in_sa2sin(struct sockaddr *, struct sockaddr_in **);
|
||||
|
||||
int route_cache(struct route *, struct in_addr, u_int);
|
||||
|
||||
char *inet_ntoa(struct in_addr);
|
||||
int inet_nat64(int, const void *, void *, const void *, u_int8_t);
|
||||
int inet_nat46(int, const void *, void *, const void *, u_int8_t);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: in_pcb.c,v 1.292 2024/02/11 01:27:45 bluhm Exp $ */
|
||||
/* $OpenBSD: in_pcb.c,v 1.293 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -920,7 +920,7 @@ in_pcbrtentry(struct inpcb *inp)
|
|||
if (inp->inp_faddr.s_addr == INADDR_ANY)
|
||||
return (NULL);
|
||||
if (route_cache(ro, inp->inp_faddr, inp->inp_rtableid)) {
|
||||
ro->ro_rt = rtalloc_mpath(&ro->ro_dst,
|
||||
ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa,
|
||||
&inp->inp_laddr.s_addr, ro->ro_tableid);
|
||||
}
|
||||
return (ro->ro_rt);
|
||||
|
@ -984,7 +984,7 @@ in_pcbselsrc(struct in_addr *insrc, struct sockaddr_in *sin,
|
|||
*/
|
||||
if (route_cache(ro, sin->sin_addr, rtableid)) {
|
||||
/* No route yet, so try to acquire one */
|
||||
ro->ro_rt = rtalloc_mpath(&ro->ro_dst, NULL, ro->ro_tableid);
|
||||
ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, NULL, ro->ro_tableid);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: in_pcb.h,v 1.151 2024/02/11 01:27:45 bluhm Exp $ */
|
||||
/* $OpenBSD: in_pcb.h,v 1.152 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -150,12 +150,7 @@ struct inpcb {
|
|||
u_int16_t inp_lport; /* [t] local port */
|
||||
struct socket *inp_socket; /* [I] back pointer to socket */
|
||||
caddr_t inp_ppcb; /* pointer to per-protocol pcb */
|
||||
union { /* Route (notice increased size). */
|
||||
struct route ru_route;
|
||||
struct route_in6 ru_route6;
|
||||
} inp_ru;
|
||||
#define inp_route inp_ru.ru_route
|
||||
#define inp_route6 inp_ru.ru_route6
|
||||
struct route inp_route; /* cached route */
|
||||
struct refcnt inp_refcnt; /* refcount PCB, delay memory free */
|
||||
struct mutex inp_mtx; /* protect PCB and socket members */
|
||||
int inp_flags; /* generic IP/datagram flags */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ip_carp.c,v 1.360 2023/12/23 10:52:54 bluhm Exp $ */
|
||||
/* $OpenBSD: ip_carp.c,v 1.361 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 Michael Shalayeff. All rights reserved.
|
||||
|
@ -54,6 +54,7 @@
|
|||
#include <net/if_var.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/netisr.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <crypto/sha1.h>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ip_input.c,v 1.388 2024/01/31 14:56:42 bluhm Exp $ */
|
||||
/* $OpenBSD: ip_input.c,v 1.389 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -1494,7 +1494,7 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt)
|
|||
route_cache(&ro, ip->ip_dst, m->m_pkthdr.ph_rtableid);
|
||||
if (!rtisvalid(rt)) {
|
||||
rtfree(rt);
|
||||
rt = rtalloc_mpath(&ro.ro_dst, &ip->ip_src.s_addr,
|
||||
rt = rtalloc_mpath(&ro.ro_dstsa, &ip->ip_src.s_addr,
|
||||
m->m_pkthdr.ph_rtableid);
|
||||
if (rt == NULL) {
|
||||
ipstat_inc(ips_noroute);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ip_output.c,v 1.394 2024/01/31 14:56:43 bluhm Exp $ */
|
||||
/* $OpenBSD: ip_output.c,v 1.395 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -167,7 +167,7 @@ reroute:
|
|||
* destination and is still up. If not, free it and try again.
|
||||
*/
|
||||
route_cache(ro, ip->ip_dst, m->m_pkthdr.ph_rtableid);
|
||||
dst = satosin(&ro->ro_dst);
|
||||
dst = &ro->ro_dstsin;
|
||||
|
||||
if ((IN_MULTICAST(ip->ip_dst.s_addr) ||
|
||||
(ip->ip_dst.s_addr == INADDR_BROADCAST)) &&
|
||||
|
@ -185,7 +185,7 @@ reroute:
|
|||
struct in_ifaddr *ia;
|
||||
|
||||
if (ro->ro_rt == NULL)
|
||||
ro->ro_rt = rtalloc_mpath(&ro->ro_dst,
|
||||
ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa,
|
||||
&ip->ip_src.s_addr, ro->ro_tableid);
|
||||
|
||||
if (ro->ro_rt == NULL) {
|
||||
|
@ -253,7 +253,7 @@ reroute:
|
|||
* still points to the address in "ro". (It may have been
|
||||
* changed to point to a gateway address, above.)
|
||||
*/
|
||||
dst = satosin(&ro->ro_dst);
|
||||
dst = &ro->ro_dstsin;
|
||||
|
||||
/*
|
||||
* See if the caller provided any multicast options
|
||||
|
@ -455,7 +455,7 @@ sendit:
|
|||
rtfree(ro->ro_rt);
|
||||
ro->ro_tableid = orig_rtableid;
|
||||
ro->ro_rt = icmp_mtudisc_clone(
|
||||
satosin(&ro->ro_dst)->sin_addr, ro->ro_tableid, 0);
|
||||
ro->ro_dstsin.sin_addr, ro->ro_tableid, 0);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
|
@ -558,7 +558,8 @@ ip_output_ipsec_pmtu_update(struct tdb *tdb, struct route *ro,
|
|||
rt->rt_mtu = tdb->tdb_mtu;
|
||||
if (ro != NULL && ro->ro_rt != NULL) {
|
||||
rtfree(ro->ro_rt);
|
||||
ro->ro_rt = rtalloc(&ro->ro_dst, RT_RESOLVE, rtableid);
|
||||
ro->ro_rt = rtalloc(&ro->ro_dstsa, RT_RESOLVE,
|
||||
rtableid);
|
||||
}
|
||||
if (rt_mtucloned)
|
||||
rtfree(rt);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ip_var.h,v 1.112 2024/02/05 23:16:39 bluhm Exp $ */
|
||||
/* $OpenBSD: ip_var.h,v 1.113 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $NetBSD: ip_var.h,v 1.16 1996/02/13 23:43:20 christos Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -227,6 +227,7 @@ extern const struct pr_usrreqs rip_usrreqs;
|
|||
|
||||
extern struct rttimer_queue ip_mtudisc_timeout_q;
|
||||
extern struct pool ipqent_pool;
|
||||
struct rtentry;
|
||||
struct route;
|
||||
struct inpcb;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: tcp_input.c,v 1.400 2024/02/11 01:27:45 bluhm Exp $ */
|
||||
/* $OpenBSD: tcp_input.c,v 1.401 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -145,8 +145,8 @@ struct timeval tcp_ackdrop_ppslim_last;
|
|||
#define ND6_HINT(tp) \
|
||||
do { \
|
||||
if (tp && tp->t_inpcb && (tp->t_inpcb->inp_flags & INP_IPV6) && \
|
||||
rtisvalid(tp->t_inpcb->inp_route6.ro_rt)) { \
|
||||
nd6_nud_hint(tp->t_inpcb->inp_route6.ro_rt); \
|
||||
rtisvalid(tp->t_inpcb->inp_route.ro_rt)) { \
|
||||
nd6_nud_hint(tp->t_inpcb->inp_route.ro_rt); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
|
@ -3166,7 +3166,7 @@ syn_cache_put(struct syn_cache *sc)
|
|||
|
||||
/* Dealing with last reference, no lock needed. */
|
||||
m_free(sc->sc_ipopts);
|
||||
rtfree(sc->sc_route4.ro_rt);
|
||||
rtfree(sc->sc_route.ro_rt);
|
||||
|
||||
pool_put(&syn_cache_pool, sc);
|
||||
}
|
||||
|
@ -3578,13 +3578,8 @@ syn_cache_get(struct sockaddr *src, struct sockaddr *dst, struct tcphdr *th,
|
|||
/*
|
||||
* Give the new socket our cached route reference.
|
||||
*/
|
||||
if (src->sa_family == AF_INET)
|
||||
inp->inp_route = sc->sc_route4; /* struct assignment */
|
||||
#ifdef INET6
|
||||
else
|
||||
inp->inp_route6 = sc->sc_route6;
|
||||
#endif
|
||||
sc->sc_route4.ro_rt = NULL;
|
||||
inp->inp_route = sc->sc_route; /* struct assignment */
|
||||
sc->sc_route.ro_rt = NULL;
|
||||
|
||||
am = m_get(M_DONTWAIT, MT_SONAME); /* XXX */
|
||||
if (am == NULL)
|
||||
|
@ -4152,7 +4147,7 @@ syn_cache_respond(struct syn_cache *sc, struct mbuf *m, uint64_t now)
|
|||
if (inp != NULL)
|
||||
ip->ip_tos = inp->inp_ip.ip_tos;
|
||||
|
||||
error = ip_output(m, sc->sc_ipopts, &sc->sc_route4,
|
||||
error = ip_output(m, sc->sc_ipopts, &sc->sc_route,
|
||||
(ip_mtudisc ? IP_MTUDISC : 0), NULL,
|
||||
inp ? inp->inp_seclevel : NULL, 0);
|
||||
break;
|
||||
|
@ -4164,7 +4159,7 @@ syn_cache_respond(struct syn_cache *sc, struct mbuf *m, uint64_t now)
|
|||
ip6->ip6_hlim = in6_selecthlim(inp);
|
||||
/* leave flowlabel = 0, it is legal and require no state mgmt */
|
||||
|
||||
error = ip6_output(m, NULL /*XXX*/, &sc->sc_route6, 0,
|
||||
error = ip6_output(m, NULL /*XXX*/, &sc->sc_route, 0,
|
||||
NULL, inp ? inp->inp_seclevel : NULL);
|
||||
break;
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: tcp_output.c,v 1.142 2024/02/11 01:27:45 bluhm Exp $ */
|
||||
/* $OpenBSD: tcp_output.c,v 1.143 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $NetBSD: tcp_output.c,v 1.16 1997/06/03 16:17:09 kml Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -1109,7 +1109,7 @@ send:
|
|||
#endif
|
||||
}
|
||||
error = ip6_output(m, tp->t_inpcb->inp_outputopts6,
|
||||
&tp->t_inpcb->inp_route6, 0, NULL,
|
||||
&tp->t_inpcb->inp_route, 0, NULL,
|
||||
tp->t_inpcb->inp_seclevel);
|
||||
break;
|
||||
#endif /* INET6 */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: tcp_subr.c,v 1.198 2024/02/11 01:27:45 bluhm Exp $ */
|
||||
/* $OpenBSD: tcp_subr.c,v 1.199 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -401,7 +401,7 @@ tcp_respond(struct tcpcb *tp, caddr_t template, struct tcphdr *th0,
|
|||
ip6->ip6_plen = tlen - sizeof(struct ip6_hdr);
|
||||
ip6->ip6_plen = htons(ip6->ip6_plen);
|
||||
ip6_output(m, tp ? tp->t_inpcb->inp_outputopts6 : NULL,
|
||||
tp ? &tp->t_inpcb->inp_route6 : NULL,
|
||||
tp ? &tp->t_inpcb->inp_route : NULL,
|
||||
0, NULL,
|
||||
tp ? tp->t_inpcb->inp_seclevel : NULL);
|
||||
break;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: tcp_var.h,v 1.175 2024/01/27 21:13:46 bluhm Exp $ */
|
||||
/* $OpenBSD: tcp_var.h,v 1.176 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -247,16 +247,7 @@ struct syn_cache {
|
|||
TAILQ_ENTRY(syn_cache) sc_bucketq; /* [S] link on bucket list */
|
||||
struct refcnt sc_refcnt; /* ref count list and timer */
|
||||
struct timeout sc_timer; /* rexmt timer */
|
||||
union { /* cached route */
|
||||
struct route route4;
|
||||
#ifdef INET6
|
||||
struct route_in6 route6;
|
||||
#endif
|
||||
} sc_route_u;
|
||||
#define sc_route4 sc_route_u.route4 /* [N] */
|
||||
#ifdef INET6
|
||||
#define sc_route6 sc_route_u.route6 /* [N] */
|
||||
#endif
|
||||
struct route sc_route; /* [N] cached route */
|
||||
long sc_win; /* [I] advertised window */
|
||||
struct syn_cache_head *sc_buckethead; /* [S] our bucket index */
|
||||
struct syn_cache_set *sc_set; /* [S] our syn cache set */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: dest6.c,v 1.19 2022/06/29 22:45:24 bluhm Exp $ */
|
||||
/* $OpenBSD: dest6.c,v 1.20 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $KAME: dest6.c,v 1.25 2001/02/22 01:39:16 itojun Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -38,6 +38,8 @@
|
|||
#include <sys/time.h>
|
||||
#include <sys/kernel.h>
|
||||
|
||||
#include <net/route.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: in6.h,v 1.115 2024/02/09 14:02:12 bluhm Exp $ */
|
||||
/* $OpenBSD: in6.h,v 1.116 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -144,16 +144,6 @@ extern const struct in6_addr in6addr_linklocal_allnodes;
|
|||
extern const struct in6_addr in6addr_linklocal_allrouters;
|
||||
|
||||
#if __BSD_VISIBLE
|
||||
/*
|
||||
* IPv6 route structure, keep fields in sync with struct route
|
||||
*/
|
||||
struct route_in6 {
|
||||
struct rtentry *ro_rt;
|
||||
u_long ro_generation;
|
||||
u_long ro_tableid; /* padded to long for alignment */
|
||||
struct sockaddr_in6 ro_dst;
|
||||
};
|
||||
|
||||
/*
|
||||
* Definition of some useful macros to handle IP6 addresses
|
||||
*/
|
||||
|
@ -428,8 +418,6 @@ int in6_mask2len(struct in6_addr *, u_char *);
|
|||
int in6_nam2sin6(const struct mbuf *, struct sockaddr_in6 **);
|
||||
int in6_sa2sin6(struct sockaddr *, struct sockaddr_in6 **);
|
||||
|
||||
int route6_cache(struct route_in6 *, const struct in6_addr *, u_int);
|
||||
|
||||
struct ip6_pktopts;
|
||||
struct ip6_moptions;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: in6_pcb.c,v 1.137 2024/02/11 01:27:45 bluhm Exp $ */
|
||||
/* $OpenBSD: in6_pcb.c,v 1.138 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
|
@ -114,13 +114,12 @@
|
|||
#include <net/pfvar.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet6/in6_var.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
#include <netinet/in_pcb.h>
|
||||
|
||||
#include <netinet6/in6_var.h>
|
||||
|
||||
#if NSTOEPLITZ > 0
|
||||
#include <net/toeplitz.h>
|
||||
#endif
|
||||
|
@ -517,13 +516,10 @@ in6_pcbnotify(struct inpcbtable *table, const struct sockaddr_in6 *dst,
|
|||
if ((PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) &&
|
||||
IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) &&
|
||||
inp->inp_route.ro_rt &&
|
||||
!(inp->inp_route.ro_rt->rt_flags & RTF_HOST)) {
|
||||
struct sockaddr_in6 *dst6;
|
||||
|
||||
dst6 = satosin6(&inp->inp_route.ro_dst);
|
||||
if (IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr,
|
||||
&dst->sin6_addr))
|
||||
goto do_notify;
|
||||
!(inp->inp_route.ro_rt->rt_flags & RTF_HOST) &&
|
||||
IN6_ARE_ADDR_EQUAL(&inp->inp_route.ro_dstsin6.sin6_addr,
|
||||
&dst->sin6_addr)) {
|
||||
goto do_notify;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -565,12 +561,12 @@ in6_pcbnotify(struct inpcbtable *table, const struct sockaddr_in6 *dst,
|
|||
struct rtentry *
|
||||
in6_pcbrtentry(struct inpcb *inp)
|
||||
{
|
||||
struct route_in6 *ro = &inp->inp_route6;
|
||||
struct route *ro = &inp->inp_route;
|
||||
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
|
||||
return (NULL);
|
||||
if (route6_cache(ro, &inp->inp_faddr6, inp->inp_rtableid)) {
|
||||
ro->ro_rt = rtalloc_mpath(sin6tosa(&ro->ro_dst),
|
||||
ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa,
|
||||
&inp->inp_laddr6.s6_addr32[0], ro->ro_tableid);
|
||||
}
|
||||
return (ro->ro_rt);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: in6_src.c,v 1.93 2024/02/09 14:02:12 bluhm Exp $ */
|
||||
/* $OpenBSD: in6_src.c,v 1.94 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $KAME: in6_src.c,v 1.36 2001/02/06 04:08:17 itojun Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -83,7 +83,7 @@
|
|||
#include <netinet6/nd6.h>
|
||||
|
||||
int in6_selectif(const struct in6_addr *, struct ip6_pktopts *,
|
||||
struct ip6_moptions *, struct route_in6 *, struct ifnet **, u_int);
|
||||
struct ip6_moptions *, struct route *, struct ifnet **, u_int);
|
||||
|
||||
/*
|
||||
* Return an IPv6 address, which is the most appropriate for a given
|
||||
|
@ -95,7 +95,7 @@ in6_pcbselsrc(const struct in6_addr **in6src, struct sockaddr_in6 *dstsock,
|
|||
struct inpcb *inp, struct ip6_pktopts *opts)
|
||||
{
|
||||
struct ip6_moptions *mopts = inp->inp_moptions6;
|
||||
struct route_in6 *ro = &inp->inp_route6;
|
||||
struct route *ro = &inp->inp_route;
|
||||
const struct in6_addr *laddr = &inp->inp_laddr6;
|
||||
u_int rtableid = inp->inp_rtableid;
|
||||
struct ifnet *ifp = NULL;
|
||||
|
@ -180,8 +180,7 @@ in6_pcbselsrc(const struct in6_addr **in6src, struct sockaddr_in6 *dstsock,
|
|||
* our src addr is taken from the i/f, else punt.
|
||||
*/
|
||||
if (route6_cache(ro, dst, rtableid)) {
|
||||
ro->ro_rt = rtalloc(sin6tosa(&ro->ro_dst),
|
||||
RT_RESOLVE, ro->ro_tableid);
|
||||
ro->ro_rt = rtalloc(&ro->ro_dstsa, RT_RESOLVE, ro->ro_tableid);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -298,7 +297,7 @@ in6_selectsrc(const struct in6_addr **in6src, struct sockaddr_in6 *dstsock,
|
|||
|
||||
struct rtentry *
|
||||
in6_selectroute(const struct in6_addr *dst, struct ip6_pktopts *opts,
|
||||
struct route_in6 *ro, unsigned int rtableid)
|
||||
struct route *ro, unsigned int rtableid)
|
||||
{
|
||||
/*
|
||||
* Use a cached route if it exists and is valid, else try to allocate
|
||||
|
@ -307,8 +306,8 @@ in6_selectroute(const struct in6_addr *dst, struct ip6_pktopts *opts,
|
|||
if (ro) {
|
||||
if (route6_cache(ro, dst, rtableid)) {
|
||||
/* No route yet, so try to acquire one */
|
||||
ro->ro_rt = rtalloc_mpath(sin6tosa(&ro->ro_dst),
|
||||
NULL, ro->ro_tableid);
|
||||
ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, NULL,
|
||||
ro->ro_tableid);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -336,7 +335,7 @@ in6_selectroute(const struct in6_addr *dst, struct ip6_pktopts *opts,
|
|||
|
||||
int
|
||||
in6_selectif(const struct in6_addr *dst, struct ip6_pktopts *opts,
|
||||
struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp,
|
||||
struct ip6_moptions *mopts, struct route *ro, struct ifnet **retifp,
|
||||
u_int rtableid)
|
||||
{
|
||||
struct rtentry *rt = NULL;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ip6_divert.c,v 1.94 2024/02/11 18:14:27 mvs Exp $ */
|
||||
/* $OpenBSD: ip6_divert.c,v 1.95 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
|
||||
|
@ -30,13 +30,13 @@
|
|||
#include <net/netisr.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet6/in6_var.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/in_pcb.h>
|
||||
#include <netinet/ip_divert.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
#include <netinet6/in6_var.h>
|
||||
#include <netinet/in_pcb.h>
|
||||
#include <netinet/ip_divert.h>
|
||||
#include <netinet6/ip6_divert.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/udp.h>
|
||||
|
@ -180,7 +180,7 @@ divert6_output(struct inpcb *inp, struct mbuf *m, struct mbuf *nam,
|
|||
} else {
|
||||
m->m_pkthdr.ph_rtableid = inp->inp_rtableid;
|
||||
|
||||
error = ip6_output(m, NULL, &inp->inp_route6,
|
||||
error = ip6_output(m, NULL, &inp->inp_route,
|
||||
IP_ALLOWBROADCAST | IP_RAWOUTPUT, NULL, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ip6_forward.c,v 1.113 2024/02/07 23:40:40 bluhm Exp $ */
|
||||
/* $OpenBSD: ip6_forward.c,v 1.114 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -86,7 +86,7 @@ ip6_forward(struct mbuf *m, struct rtentry *rt, int srcrt)
|
|||
{
|
||||
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
||||
struct sockaddr *dst;
|
||||
struct route_in6 ro;
|
||||
struct route ro;
|
||||
struct ifnet *ifp = NULL;
|
||||
int error = 0, type = 0, code = 0, destmtu = 0;
|
||||
struct mbuf *mcopy = NULL;
|
||||
|
@ -167,7 +167,7 @@ reroute:
|
|||
|
||||
ro.ro_rt = NULL;
|
||||
route6_cache(&ro, &ip6->ip6_dst, m->m_pkthdr.ph_rtableid);
|
||||
dst = sin6tosa(&ro.ro_dst);
|
||||
dst = &ro.ro_dstsa;
|
||||
if (!rtisvalid(rt)) {
|
||||
rtfree(rt);
|
||||
rt = rtalloc_mpath(dst, &ip6->ip6_src.s6_addr32[0],
|
||||
|
@ -253,7 +253,7 @@ reroute:
|
|||
ip6_sendredirects &&
|
||||
(rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
|
||||
if ((ifp->if_flags & IFF_POINTOPOINT) &&
|
||||
nd6_is_addr_neighbor(&ro.ro_dst, ifp)) {
|
||||
nd6_is_addr_neighbor(&ro.ro_dstsin6, ifp)) {
|
||||
/*
|
||||
* If the incoming interface is equal to the outgoing
|
||||
* one, the link attached to the interface is
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ip6_id.c,v 1.16 2021/03/10 10:21:49 jsg Exp $ */
|
||||
/* $OpenBSD: ip6_id.c,v 1.17 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $NetBSD: ip6_id.c,v 1.7 2003/09/13 21:32:59 itojun Exp $ */
|
||||
/* $KAME: ip6_id.c,v 1.8 2003/09/06 13:41:06 itojun Exp $ */
|
||||
|
||||
|
@ -89,7 +89,6 @@
|
|||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
|
||||
struct randomtab {
|
||||
const int ru_bits; /* resulting bits */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ip6_output.c,v 1.285 2024/02/07 23:40:40 bluhm Exp $ */
|
||||
/* $OpenBSD: ip6_output.c,v 1.286 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -143,7 +143,7 @@ static __inline u_int16_t __attribute__((__unused__))
|
|||
u_int32_t, u_int32_t);
|
||||
void in6_delayed_cksum(struct mbuf *, u_int8_t);
|
||||
|
||||
int ip6_output_ipsec_pmtu_update(struct tdb *, struct route_in6 *,
|
||||
int ip6_output_ipsec_pmtu_update(struct tdb *, struct route *,
|
||||
struct in6_addr *, int, int, int);
|
||||
|
||||
/* Context for non-repeating IDs */
|
||||
|
@ -160,14 +160,14 @@ struct idgen32_ctx ip6_id_ctx;
|
|||
* We use u_long to hold largest one, * which is rt_mtu.
|
||||
*/
|
||||
int
|
||||
ip6_output(struct mbuf *m, struct ip6_pktopts *opt, struct route_in6 *ro,
|
||||
ip6_output(struct mbuf *m, struct ip6_pktopts *opt, struct route *ro,
|
||||
int flags, struct ip6_moptions *im6o, const u_char seclevel[])
|
||||
{
|
||||
struct ip6_hdr *ip6;
|
||||
struct ifnet *ifp = NULL;
|
||||
struct mbuf_list ml;
|
||||
int hlen, tlen;
|
||||
struct route_in6 ip6route;
|
||||
struct route iproute;
|
||||
struct rtentry *rt = NULL;
|
||||
struct sockaddr_in6 *dst;
|
||||
int error = 0;
|
||||
|
@ -177,7 +177,7 @@ ip6_output(struct mbuf *m, struct ip6_pktopts *opt, struct route_in6 *ro,
|
|||
u_int32_t optlen = 0, plen = 0, unfragpartlen = 0;
|
||||
struct ip6_exthdrs exthdrs;
|
||||
struct in6_addr finaldst;
|
||||
struct route_in6 *ro_pmtu = NULL;
|
||||
struct route *ro_pmtu = NULL;
|
||||
int hdrsplit = 0;
|
||||
u_int8_t sproto = 0;
|
||||
u_char nextproto;
|
||||
|
@ -390,13 +390,13 @@ reroute:
|
|||
|
||||
/* initialize cached route */
|
||||
if (ro == NULL) {
|
||||
ro = &ip6route;
|
||||
ro = &iproute;
|
||||
bzero((caddr_t)ro, sizeof(*ro));
|
||||
}
|
||||
ro_pmtu = ro;
|
||||
if (opt && opt->ip6po_rthdr)
|
||||
ro = &opt->ip6po_route;
|
||||
dst = &ro->ro_dst;
|
||||
dst = &ro->ro_dstsin6;
|
||||
|
||||
/*
|
||||
* if specified, try to fill in the traffic class field.
|
||||
|
@ -750,9 +750,9 @@ reroute:
|
|||
ip6stat_inc(ip6s_fragmented);
|
||||
|
||||
done:
|
||||
if (ro == &ip6route && ro->ro_rt) {
|
||||
if (ro == &iproute && ro->ro_rt) {
|
||||
rtfree(ro->ro_rt);
|
||||
} else if (ro_pmtu == &ip6route && ro_pmtu->ro_rt) {
|
||||
} else if (ro_pmtu == &iproute && ro_pmtu->ro_rt) {
|
||||
rtfree(ro_pmtu->ro_rt);
|
||||
}
|
||||
if_put(ifp);
|
||||
|
@ -2772,7 +2772,7 @@ ip6_output_ipsec_lookup(struct mbuf *m, const u_char seclevel[],
|
|||
}
|
||||
|
||||
int
|
||||
ip6_output_ipsec_pmtu_update(struct tdb *tdb, struct route_in6 *ro,
|
||||
ip6_output_ipsec_pmtu_update(struct tdb *tdb, struct route *ro,
|
||||
struct in6_addr *dst, int ifidx, int rtableid, int transportmode)
|
||||
{
|
||||
struct rtentry *rt = NULL;
|
||||
|
@ -2807,7 +2807,7 @@ ip6_output_ipsec_pmtu_update(struct tdb *tdb, struct route_in6 *ro,
|
|||
rt->rt_mtu = tdb->tdb_mtu;
|
||||
if (ro != NULL && ro->ro_rt != NULL) {
|
||||
rtfree(ro->ro_rt);
|
||||
ro->ro_rt = rtalloc(sin6tosa(&ro->ro_dst), RT_RESOLVE,
|
||||
ro->ro_rt = rtalloc(&ro->ro_dstsa, RT_RESOLVE,
|
||||
rtableid);
|
||||
}
|
||||
if (rt_mtucloned)
|
||||
|
@ -2817,7 +2817,7 @@ ip6_output_ipsec_pmtu_update(struct tdb *tdb, struct route_in6 *ro,
|
|||
}
|
||||
|
||||
int
|
||||
ip6_output_ipsec_send(struct tdb *tdb, struct mbuf *m, struct route_in6 *ro,
|
||||
ip6_output_ipsec_send(struct tdb *tdb, struct mbuf *m, struct route *ro,
|
||||
int tunalready, int fwd)
|
||||
{
|
||||
struct mbuf_list ml;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ip6_var.h,v 1.112 2024/02/07 23:40:40 bluhm Exp $ */
|
||||
/* $OpenBSD: ip6_var.h,v 1.113 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -103,7 +103,7 @@ struct ip6_moptions {
|
|||
/* Routing header related info */
|
||||
struct ip6po_rhinfo {
|
||||
struct ip6_rthdr *ip6po_rhi_rthdr; /* Routing header */
|
||||
struct route_in6 ip6po_rhi_route; /* Route to the 1st hop */
|
||||
struct route ip6po_rhi_route; /* Route to the 1st hop */
|
||||
};
|
||||
#define ip6po_rthdr ip6po_rhinfo.ip6po_rhi_rthdr
|
||||
#define ip6po_route ip6po_rhinfo.ip6po_rhi_route
|
||||
|
@ -323,7 +323,7 @@ int ip6_sysctl(int *, u_int, void *, size_t *, void *, size_t);
|
|||
void ip6_forward(struct mbuf *, struct rtentry *, int);
|
||||
|
||||
void ip6_mloopback(struct ifnet *, struct mbuf *, struct sockaddr_in6 *);
|
||||
int ip6_output(struct mbuf *, struct ip6_pktopts *, struct route_in6 *, int,
|
||||
int ip6_output(struct mbuf *, struct ip6_pktopts *, struct route *, int,
|
||||
struct ip6_moptions *, const u_char[]);
|
||||
int ip6_fragment(struct mbuf *, struct mbuf_list *, int, u_char, u_long);
|
||||
int ip6_ctloutput(int, struct socket *, int, int, struct mbuf *);
|
||||
|
@ -370,14 +370,14 @@ int in6_pcbselsrc(const struct in6_addr **, struct sockaddr_in6 *,
|
|||
int in6_selectsrc(const struct in6_addr **, struct sockaddr_in6 *,
|
||||
struct ip6_moptions *, unsigned int);
|
||||
struct rtentry *in6_selectroute(const struct in6_addr *, struct ip6_pktopts *,
|
||||
struct route_in6 *, unsigned int rtableid);
|
||||
struct route *, unsigned int rtableid);
|
||||
|
||||
u_int32_t ip6_randomflowlabel(void);
|
||||
|
||||
#ifdef IPSEC
|
||||
struct tdb;
|
||||
int ip6_output_ipsec_lookup(struct mbuf *, const u_char[], struct tdb **);
|
||||
int ip6_output_ipsec_send(struct tdb *, struct mbuf *, struct route_in6 *,
|
||||
int ip6_output_ipsec_send(struct tdb *, struct mbuf *, struct route *,
|
||||
int, int);
|
||||
#endif /* IPSEC */
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: mld6.c,v 1.61 2022/09/08 10:22:07 kn Exp $ */
|
||||
/* $OpenBSD: mld6.c,v 1.62 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $KAME: mld6.c,v 1.26 2001/02/16 14:50:35 itojun Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -74,6 +74,7 @@
|
|||
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet6/in6_var.h>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: raw_ip6.c,v 1.181 2024/02/11 18:14:27 mvs Exp $ */
|
||||
/* $OpenBSD: raw_ip6.c,v 1.182 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $KAME: raw_ip6.c,v 1.69 2001/03/04 15:55:44 itojun Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -512,7 +512,7 @@ rip6_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr,
|
|||
pf_mbuf_link_inpcb(m, inp);
|
||||
#endif
|
||||
|
||||
error = ip6_output(m, optp, &inp->inp_route6, flags,
|
||||
error = ip6_output(m, optp, &inp->inp_route, flags,
|
||||
inp->inp_moptions6, inp->inp_seclevel);
|
||||
if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
|
||||
icmp6stat_inc(icp6s_outhist + type);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: route6.c,v 1.21 2017/04/14 20:46:31 bluhm Exp $ */
|
||||
/* $OpenBSD: route6.c,v 1.22 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $KAME: route6.c,v 1.22 2000/12/03 00:54:00 itojun Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet6/in6_var.h>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: udp6_output.c,v 1.63 2023/12/03 20:36:24 bluhm Exp $ */
|
||||
/* $OpenBSD: udp6_output.c,v 1.64 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $KAME: udp6_output.c,v 1.21 2001/02/07 11:51:54 itojun Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -232,7 +232,7 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct mbuf *addr6,
|
|||
pf_mbuf_link_inpcb(m, inp);
|
||||
#endif
|
||||
|
||||
error = ip6_output(m, optp, &inp->inp_route6,
|
||||
error = ip6_output(m, optp, &inp->inp_route,
|
||||
flags, inp->inp_moptions6, inp->inp_seclevel);
|
||||
goto releaseopt;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: socketvar.h,v 1.123 2024/02/11 18:14:27 mvs Exp $ */
|
||||
/* $OpenBSD: socketvar.h,v 1.124 2024/02/12 22:48:27 mvs Exp $ */
|
||||
/* $NetBSD: socketvar.h,v 1.18 1996/02/09 18:25:38 christos Exp $ */
|
||||
|
||||
/*-
|
||||
|
@ -375,7 +375,7 @@ int soconnect(struct socket *, struct mbuf *);
|
|||
int soconnect2(struct socket *, struct socket *);
|
||||
int socreate(int, struct socket **, int, int);
|
||||
int sodisconnect(struct socket *);
|
||||
struct socket *soalloc(const struct domain *, int);
|
||||
struct socket *soalloc(const struct protosw *, int);
|
||||
void sofree(struct socket *, int);
|
||||
int sogetopt(struct socket *, int, int, struct mbuf *);
|
||||
void sohasoutofband(struct socket *);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: uvm_page.c,v 1.173 2023/08/12 07:22:56 mpi Exp $ */
|
||||
/* $OpenBSD: uvm_page.c,v 1.174 2024/02/13 10:16:28 miod Exp $ */
|
||||
/* $NetBSD: uvm_page.c,v 1.44 2000/11/27 08:40:04 chs Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -1024,10 +1024,6 @@ uvm_pageclean(struct vm_page *pg)
|
|||
void
|
||||
uvm_pagefree(struct vm_page *pg)
|
||||
{
|
||||
if ((pg->pg_flags & (PG_TABLED|PQ_ACTIVE|PQ_INACTIVE)) &&
|
||||
(pg->uobject == NULL || !UVM_OBJ_IS_PMAP(pg->uobject)))
|
||||
MUTEX_ASSERT_LOCKED(&uvm.pageqlock);
|
||||
|
||||
uvm_pageclean(pg);
|
||||
uvm_pmr_freepages(pg, 1);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: inet.c,v 1.180 2024/02/05 23:16:39 bluhm Exp $ */
|
||||
/* $OpenBSD: inet.c,v 1.181 2024/02/13 12:22:09 bluhm Exp $ */
|
||||
/* $NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -1461,14 +1461,14 @@ inpcb_dump(u_long off, short protocol, int af)
|
|||
case AF_INET:
|
||||
inet_ntop(af, &inp.inp_faddr, faddr, sizeof(faddr));
|
||||
inet_ntop(af, &inp.inp_laddr, laddr, sizeof(laddr));
|
||||
inet_ntop(af, &((struct sockaddr_in *)
|
||||
(&inp.inp_route.ro_dst))->sin_addr, raddr, sizeof(raddr));
|
||||
inet_ntop(af, &inp.inp_route.ro_dstsin.sin_addr, raddr,
|
||||
sizeof(raddr));
|
||||
break;
|
||||
case AF_INET6:
|
||||
inet_ntop(af, &inp.inp_faddr6, faddr, sizeof(faddr));
|
||||
inet_ntop(af, &inp.inp_laddr6, laddr, sizeof(laddr));
|
||||
inet_ntop(af, &inp.inp_route6.ro_dst.sin6_addr,
|
||||
raddr, sizeof(raddr));
|
||||
inet_ntop(af, &inp.inp_route.ro_dstsin6.sin6_addr, raddr,
|
||||
sizeof(raddr));
|
||||
break;
|
||||
default:
|
||||
faddr[0] = laddr[0] = '\0';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: cmd-paste-buffer.c,v 1.41 2021/08/21 10:22:39 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-paste-buffer.c,v 1.42 2024/02/13 08:03:50 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
@ -55,6 +55,11 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
|||
size_t seplen, bufsize;
|
||||
int bracket = args_has(args, 'p');
|
||||
|
||||
if (window_pane_exited(wp)) {
|
||||
cmdq_error(item, "target pane has exited");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
bufname = NULL;
|
||||
if (args_has(args, 'b'))
|
||||
bufname = args_get(args, 'b');
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: cmd-pipe-pane.c,v 1.60 2022/05/30 13:03:46 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-pipe-pane.c,v 1.61 2024/02/13 08:03:50 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
@ -69,7 +69,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||
sigset_t set, oldset;
|
||||
|
||||
/* Do nothing if pane is dead. */
|
||||
if (wp->fd == -1 || (wp->flags & PANE_EXITED)) {
|
||||
if (window_pane_exited(wp)) {
|
||||
cmdq_error(item, "target pane has exited");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: options-table.c,v 1.168 2023/09/01 13:48:54 nicm Exp $ */
|
||||
/* $OpenBSD: options-table.c,v 1.169 2024/02/13 08:10:23 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
@ -85,6 +85,9 @@ static const char *options_table_window_size_list[] = {
|
|||
static const char *options_table_remain_on_exit_list[] = {
|
||||
"off", "on", "failed", NULL
|
||||
};
|
||||
static const char *options_table_destroy_unattached_list[] = {
|
||||
"off", "on", "keep-last", "keep-group", NULL
|
||||
};
|
||||
static const char *options_table_detach_on_destroy_list[] = {
|
||||
"off", "on", "no-detached", "previous", "next", NULL
|
||||
};
|
||||
|
@ -484,11 +487,12 @@ const struct options_table_entry options_table[] = {
|
|||
},
|
||||
|
||||
{ .name = "destroy-unattached",
|
||||
.type = OPTIONS_TABLE_FLAG,
|
||||
.type = OPTIONS_TABLE_CHOICE,
|
||||
.scope = OPTIONS_TABLE_SESSION,
|
||||
.choices = options_table_destroy_unattached_list,
|
||||
.default_num = 0,
|
||||
.text = "Whether to destroy sessions when they have no attached "
|
||||
"clients."
|
||||
"clients, or keep the last session whether in the group."
|
||||
},
|
||||
|
||||
{ .name = "detach-on-destroy",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: proc.c,v 1.23 2024/01/16 13:09:11 claudio Exp $ */
|
||||
/* $OpenBSD: proc.c,v 1.24 2024/02/13 08:10:23 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
@ -92,7 +92,7 @@ proc_event_cb(__unused int fd, short events, void *arg)
|
|||
log_debug("peer %p message %d", peer, imsg.hdr.type);
|
||||
|
||||
if (peer_check_version(peer, &imsg) != 0) {
|
||||
int fd = imsg_get_fd(&imsg);
|
||||
fd = imsg_get_fd(&imsg);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
imsg_free(&imsg);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: server-fn.c,v 1.134 2023/09/01 13:48:54 nicm Exp $ */
|
||||
/* $OpenBSD: server-fn.c,v 1.135 2024/02/13 08:10:23 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
@ -454,7 +454,8 @@ server_destroy_session(struct session *s)
|
|||
void
|
||||
server_check_unattached(void)
|
||||
{
|
||||
struct session *s;
|
||||
struct session *s;
|
||||
struct session_group *sg;
|
||||
|
||||
/*
|
||||
* If any sessions are no longer attached and have destroy-unattached
|
||||
|
@ -463,8 +464,23 @@ server_check_unattached(void)
|
|||
RB_FOREACH(s, sessions, &sessions) {
|
||||
if (s->attached != 0)
|
||||
continue;
|
||||
if (options_get_number (s->options, "destroy-unattached"))
|
||||
session_destroy(s, 1, __func__);
|
||||
switch (options_get_number(s->options, "destroy-unattached")) {
|
||||
case 0: /* off */
|
||||
continue;
|
||||
case 1: /* on */
|
||||
break;
|
||||
case 2: /* keep-last */
|
||||
sg = session_group_contains(s);
|
||||
if (sg == NULL || session_group_count(sg) <= 1)
|
||||
continue;
|
||||
break;
|
||||
case 3: /* keep-group */
|
||||
sg = session_group_contains(s);
|
||||
if (sg != NULL && session_group_count(sg) == 1)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
session_destroy(s, 1, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.\" $OpenBSD: tmux.1,v 1.935 2023/12/27 20:23:59 nicm Exp $
|
||||
.\" $OpenBSD: tmux.1,v 1.936 2024/02/13 08:10:23 nicm Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
.\"
|
||||
|
@ -14,7 +14,7 @@
|
|||
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: December 27 2023 $
|
||||
.Dd $Mdocdate: February 13 2024 $
|
||||
.Dt TMUX 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -4023,10 +4023,20 @@ The value is the width and height separated by an
|
|||
character.
|
||||
The default is 80x24.
|
||||
.It Xo Ic destroy-unattached
|
||||
.Op Ic on | off
|
||||
.Op Ic off | on | keep-last | keep-group
|
||||
.Xc
|
||||
If enabled and the session is no longer attached to any clients, it is
|
||||
destroyed.
|
||||
If
|
||||
.Ic on ,
|
||||
destroy the session after the last client has detached.
|
||||
If
|
||||
.Ic off
|
||||
(the default), leave the session orphaned.
|
||||
If
|
||||
.Ic keep-last ,
|
||||
destroy the session only if it is in a group and has other sessions in that group.
|
||||
If
|
||||
.Ic keep-group ,
|
||||
destroy the session unless it is in a group and is the only session in that group.
|
||||
.It Xo Ic detach-on-destroy
|
||||
.Op Ic off | on | no-detached | previous | next
|
||||
.Xc
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: tmux.h,v 1.1211 2023/09/15 15:49:05 nicm Exp $ */
|
||||
/* $OpenBSD: tmux.h,v 1.1212 2024/02/13 08:03:50 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
@ -3047,6 +3047,7 @@ int window_pane_key(struct window_pane *, struct client *,
|
|||
struct session *, struct winlink *, key_code,
|
||||
struct mouse_event *);
|
||||
int window_pane_visible(struct window_pane *);
|
||||
int window_pane_exited(struct window_pane *);
|
||||
u_int window_pane_search(struct window_pane *, const char *, int,
|
||||
int);
|
||||
const char *window_printable_flags(struct winlink *, int);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: window.c,v 1.287 2023/10/23 08:12:00 nicm Exp $ */
|
||||
/* $OpenBSD: window.c,v 1.288 2024/02/13 08:03:50 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
@ -1204,6 +1204,12 @@ window_pane_visible(struct window_pane *wp)
|
|||
return (wp == wp->window->active);
|
||||
}
|
||||
|
||||
int
|
||||
window_pane_exited(struct window_pane *wp)
|
||||
{
|
||||
return (wp->fd == -1 || (wp->flags & PANE_EXITED));
|
||||
}
|
||||
|
||||
u_int
|
||||
window_pane_search(struct window_pane *wp, const char *term, int regex,
|
||||
int ignore)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: bgpd.h,v 1.484 2024/01/30 13:50:08 claudio Exp $ */
|
||||
/* $OpenBSD: bgpd.h,v 1.485 2024/02/13 16:35:43 claudio Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
|
||||
|
@ -197,14 +197,12 @@ struct bgpd_addr {
|
|||
struct in_addr v4;
|
||||
struct in6_addr v6;
|
||||
/* maximum size for a prefix is 256 bits */
|
||||
} ba; /* 128-bit address */
|
||||
}; /* 128-bit address */
|
||||
uint64_t rd; /* route distinguisher for VPN addrs */
|
||||
uint32_t scope_id; /* iface scope id for v6 */
|
||||
uint8_t aid;
|
||||
uint8_t labellen; /* size of the labelstack */
|
||||
uint8_t labelstack[18]; /* max that makes sense */
|
||||
#define v4 ba.v4
|
||||
#define v6 ba.v6
|
||||
};
|
||||
|
||||
#define DEFAULT_LISTENER 0x01
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: pftable.c,v 1.17 2022/08/17 15:15:26 claudio Exp $ */
|
||||
/* $OpenBSD: pftable.c,v 1.18 2024/02/13 16:35:43 claudio Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004 Damien Miller <djm@openbsd.org>
|
||||
|
@ -31,12 +31,9 @@
|
|||
|
||||
#include "log.h"
|
||||
|
||||
/* Namespace collision: these are defined in both bgpd.h and pfvar.h */
|
||||
/* Namespace collision: these are defined in pfvar.h and bgpd.h */
|
||||
#undef v4
|
||||
#undef v6
|
||||
#undef addr8
|
||||
#undef addr16
|
||||
#undef addr32
|
||||
|
||||
#include "bgpd.h"
|
||||
|
||||
|
@ -216,7 +213,7 @@ pftable_add_work(const char *table, struct bgpd_addr *addr,
|
|||
pfa = &pft->worklist[pft->naddrs];
|
||||
|
||||
memset(pfa, 0, sizeof(*pfa));
|
||||
memcpy(&pfa->pfra_u, &addr->ba, (len + 7U) / 8);
|
||||
memcpy(&pfa->pfra_u, &addr->v6, (len + 7U) / 8);
|
||||
pfa->pfra_af = aid2af(addr->aid);
|
||||
pfa->pfra_net = len;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: session.c,v 1.461 2024/01/18 14:56:44 claudio Exp $ */
|
||||
/* $OpenBSD: session.c,v 1.462 2024/02/13 16:12:37 claudio Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
|
||||
|
@ -3344,15 +3344,6 @@ session_dispatch_imsg(struct imsgbuf *imsgbuf, int idx, u_int *listener_cnt)
|
|||
"IMSG_SESSION_RESTARTED");
|
||||
}
|
||||
break;
|
||||
case IMSG_SESSION_DOWN:
|
||||
if (idx != PFD_PIPE_ROUTE)
|
||||
fatalx("session down not from RDE");
|
||||
if ((p = getpeerbyid(conf, peerid)) == NULL) {
|
||||
log_warnx("no such peer: id=%u", peerid);
|
||||
break;
|
||||
}
|
||||
session_stop(p, ERR_CEASE_ADMIN_DOWN);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: server_http.c,v 1.153 2022/09/21 05:55:18 yasuoka Exp $ */
|
||||
/* $OpenBSD: server_http.c,v 1.154 2024/02/13 14:00:24 claudio Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Matthias Pressfreund <mpfr@fn.de>
|
||||
|
@ -1762,13 +1762,14 @@ read_errdoc(const char *root, const char *file)
|
|||
struct stat sb;
|
||||
char *path;
|
||||
int fd;
|
||||
char *ret = NULL;
|
||||
char *ret;
|
||||
|
||||
if (asprintf(&path, "%s/%s.html", root, file) == -1)
|
||||
fatal("asprintf");
|
||||
if ((fd = open(path, O_RDONLY)) == -1) {
|
||||
free(path);
|
||||
log_warn("%s: open", __func__);
|
||||
if (errno != ENOENT)
|
||||
log_warn("%s: open", __func__);
|
||||
return (NULL);
|
||||
}
|
||||
free(path);
|
||||
|
@ -1788,8 +1789,7 @@ read_errdoc(const char *root, const char *file)
|
|||
log_warn("%s: read", __func__);
|
||||
close(fd);
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
return (ret);
|
||||
return (NULL);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
|
|
|
@ -7771,6 +7771,7 @@ static int zonemd_dnssec_verify_rrset(struct auth_zone* z,
|
|||
enum sec_status sec;
|
||||
struct val_env* ve;
|
||||
int m;
|
||||
int verified = 0;
|
||||
m = modstack_find(mods, "validator");
|
||||
if(m == -1) {
|
||||
auth_zone_log(z->name, VERB_ALGO, "zonemd dnssec verify: have "
|
||||
|
@ -7794,7 +7795,7 @@ 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);
|
||||
LDNS_SECTION_ANSWER, NULL, &verified);
|
||||
if(sec == sec_status_secure) {
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -690,6 +690,28 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
|
|||
return msg;
|
||||
}
|
||||
|
||||
struct dns_msg*
|
||||
dns_msg_deepcopy_region(struct dns_msg* origin, struct regional* region)
|
||||
{
|
||||
size_t i;
|
||||
struct dns_msg* res = NULL;
|
||||
res = gen_dns_msg(region, &origin->qinfo, origin->rep->rrset_count);
|
||||
if(!res) return NULL;
|
||||
*res->rep = *origin->rep;
|
||||
if(origin->rep->reason_bogus_str) {
|
||||
res->rep->reason_bogus_str = regional_strdup(region,
|
||||
origin->rep->reason_bogus_str);
|
||||
}
|
||||
for(i=0; i<res->rep->rrset_count; i++) {
|
||||
res->rep->rrsets[i] = packed_rrset_copy_region(
|
||||
origin->rep->rrsets[i], region, 0);
|
||||
if(!res->rep->rrsets[i]) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/** synthesize RRset-only response from cached RRset item */
|
||||
static struct dns_msg*
|
||||
rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
|
|
|
@ -164,6 +164,15 @@ struct dns_msg* tomsg(struct module_env* env, struct query_info* q,
|
|||
struct reply_info* r, struct regional* region, time_t now,
|
||||
int allow_expired, struct regional* scratch);
|
||||
|
||||
/**
|
||||
* Deep copy a dns_msg to a region.
|
||||
* @param origin: the dns_msg to copy.
|
||||
* @param region: the region to copy all the data to.
|
||||
* @return the new dns_msg or NULL on malloc error.
|
||||
*/
|
||||
struct dns_msg* dns_msg_deepcopy_region(struct dns_msg* origin,
|
||||
struct regional* region);
|
||||
|
||||
/**
|
||||
* Find cached message
|
||||
* @param env: module environment with the DNS cache.
|
||||
|
|
|
@ -180,6 +180,7 @@ verifytest_rrset(struct module_env* env, struct val_env* ve,
|
|||
enum sec_status sec;
|
||||
char* reason = NULL;
|
||||
uint8_t sigalg[ALGO_NEEDS_MAX+1];
|
||||
int verified = 0;
|
||||
if(vsig) {
|
||||
log_nametypeclass(VERB_QUERY, "verify of rrset",
|
||||
rrset->rk.dname, ntohs(rrset->rk.type),
|
||||
|
@ -188,7 +189,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);
|
||||
LDNS_SECTION_ANSWER, NULL, &verified);
|
||||
if(vsig) {
|
||||
printf("verify outcome is: %s %s\n", sec_status_to_string(sec),
|
||||
reason?reason:"");
|
||||
|
@ -442,9 +443,9 @@ nsec3_hash_test_entry(struct entry* e, rbtree_type* ct,
|
|||
|
||||
ret = nsec3_hash_name(ct, region, buf, nsec3, 0, qname,
|
||||
qinfo.qname_len, &hash);
|
||||
if(ret != 1) {
|
||||
if(ret < 1) {
|
||||
printf("Bad nsec3_hash_name retcode %d\n", ret);
|
||||
unit_assert(ret == 1);
|
||||
unit_assert(ret == 1 || ret == 2);
|
||||
}
|
||||
unit_assert(hash->dname && hash->hash && hash->hash_len &&
|
||||
hash->b32 && hash->b32_len);
|
||||
|
|
|
@ -131,6 +131,7 @@ fptr_whitelist_comm_timer(void (*fptr)(void*))
|
|||
else if(fptr == &pending_udp_timer_delay_cb) return 1;
|
||||
else if(fptr == &worker_stat_timer_cb) return 1;
|
||||
else if(fptr == &worker_probe_timer_cb) return 1;
|
||||
else if(fptr == &validate_suspend_timer_cb) return 1;
|
||||
#ifdef UB_ON_WINDOWS
|
||||
else if(fptr == &wsvc_cron_cb) return 1;
|
||||
#endif
|
||||
|
|
|
@ -181,6 +181,7 @@ nsec_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
{
|
||||
struct packed_rrset_data* d = (struct packed_rrset_data*)
|
||||
nsec->entry.data;
|
||||
int verified = 0;
|
||||
if(!d) return 0;
|
||||
if(d->security == sec_status_secure)
|
||||
return 1;
|
||||
|
@ -188,7 +189,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);
|
||||
reason_bogus, LDNS_SECTION_AUTHORITY, qstate, &verified);
|
||||
if(d->security == sec_status_secure) {
|
||||
rrset_update_sec_status(env->rrset_cache, nsec, *env->now);
|
||||
return 1;
|
||||
|
|
|
@ -57,6 +57,19 @@
|
|||
/* we include nsec.h for the bitmap_has_type function */
|
||||
#include "validator/val_nsec.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
#include "util/config_file.h"
|
||||
|
||||
/**
|
||||
* Max number of NSEC3 calculations at once, suspend query for later.
|
||||
* 8 is low enough and allows for cases where multiple proofs are needed.
|
||||
*/
|
||||
#define MAX_NSEC3_CALCULATIONS 8
|
||||
/**
|
||||
* When all allowed NSEC3 calculations at once resulted in error treat as
|
||||
* bogus. NSEC3 hash errors are not cached and this helps breaks loops with
|
||||
* erroneous data.
|
||||
*/
|
||||
#define MAX_NSEC3_ERRORS -1
|
||||
|
||||
/**
|
||||
* This function we get from ldns-compat or from base system
|
||||
|
@ -532,6 +545,17 @@ nsec3_hash_cmp(const void* c1, const void* c2)
|
|||
return memcmp(s1, s2, s1len);
|
||||
}
|
||||
|
||||
int
|
||||
nsec3_cache_table_init(struct nsec3_cache_table* ct, struct regional* region)
|
||||
{
|
||||
if(ct->ct) return 1;
|
||||
ct->ct = (rbtree_type*)regional_alloc(region, sizeof(*ct->ct));
|
||||
if(!ct->ct) return 0;
|
||||
ct->region = region;
|
||||
rbtree_init(ct->ct, &nsec3_hash_cmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t
|
||||
nsec3_get_hashed(sldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo,
|
||||
size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res, size_t max)
|
||||
|
@ -646,7 +670,7 @@ nsec3_hash_name(rbtree_type* table, struct regional* region, sldns_buffer* buf,
|
|||
c = (struct nsec3_cached_hash*)rbtree_search(table, &looki);
|
||||
if(c) {
|
||||
*hash = c;
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
/* create a new entry */
|
||||
c = (struct nsec3_cached_hash*)regional_alloc(region, sizeof(*c));
|
||||
|
@ -658,10 +682,10 @@ nsec3_hash_name(rbtree_type* table, struct regional* region, sldns_buffer* buf,
|
|||
c->dname_len = dname_len;
|
||||
r = nsec3_calc_hash(region, buf, c);
|
||||
if(r != 1)
|
||||
return r;
|
||||
return r; /* returns -1 or 0 */
|
||||
r = nsec3_calc_b32(region, buf, c);
|
||||
if(r != 1)
|
||||
return r;
|
||||
return r; /* returns 0 */
|
||||
#ifdef UNBOUND_DEBUG
|
||||
n =
|
||||
#else
|
||||
|
@ -704,6 +728,7 @@ nsec3_hash_matches_owner(struct nsec3_filter* flt,
|
|||
struct nsec3_cached_hash* hash, struct ub_packed_rrset_key* s)
|
||||
{
|
||||
uint8_t* nm = s->rk.dname;
|
||||
if(!hash) return 0; /* please clang */
|
||||
/* compare, does hash of name based on params in this NSEC3
|
||||
* match the owner name of this NSEC3?
|
||||
* name must be: <hashlength>base32 . zone name
|
||||
|
@ -730,34 +755,50 @@ nsec3_hash_matches_owner(struct nsec3_filter* flt,
|
|||
* @param nmlen: length of name.
|
||||
* @param rrset: nsec3 that matches is returned here.
|
||||
* @param rr: rr number in nsec3 rrset that matches.
|
||||
* @param calculations: current hash calculations.
|
||||
* @return true if a matching NSEC3 is found, false if not.
|
||||
*/
|
||||
static int
|
||||
find_matching_nsec3(struct module_env* env, struct nsec3_filter* flt,
|
||||
rbtree_type* ct, uint8_t* nm, size_t nmlen,
|
||||
struct ub_packed_rrset_key** rrset, int* rr)
|
||||
struct nsec3_cache_table* ct, uint8_t* nm, size_t nmlen,
|
||||
struct ub_packed_rrset_key** rrset, int* rr,
|
||||
int* calculations)
|
||||
{
|
||||
size_t i_rs;
|
||||
int i_rr;
|
||||
struct ub_packed_rrset_key* s;
|
||||
struct nsec3_cached_hash* hash = NULL;
|
||||
int r;
|
||||
int calc_errors = 0;
|
||||
|
||||
/* this loop skips other-zone and unknown NSEC3s, also non-NSEC3 RRs */
|
||||
for(s=filter_first(flt, &i_rs, &i_rr); s;
|
||||
s=filter_next(flt, &i_rs, &i_rr)) {
|
||||
/* check if we are allowed more calculations */
|
||||
if(*calculations >= MAX_NSEC3_CALCULATIONS) {
|
||||
if(calc_errors == *calculations) {
|
||||
*calculations = MAX_NSEC3_ERRORS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* get name hashed for this NSEC3 RR */
|
||||
r = nsec3_hash_name(ct, env->scratch, env->scratch_buffer,
|
||||
r = nsec3_hash_name(ct->ct, ct->region, env->scratch_buffer,
|
||||
s, i_rr, nm, nmlen, &hash);
|
||||
if(r == 0) {
|
||||
log_err("nsec3: malloc failure");
|
||||
break; /* alloc failure */
|
||||
} else if(r != 1)
|
||||
continue; /* malformed NSEC3 */
|
||||
else if(nsec3_hash_matches_owner(flt, hash, s)) {
|
||||
*rrset = s; /* rrset with this name */
|
||||
*rr = i_rr; /* matches hash with these parameters */
|
||||
return 1;
|
||||
} else if(r < 0) {
|
||||
/* malformed NSEC3 */
|
||||
calc_errors++;
|
||||
(*calculations)++;
|
||||
continue;
|
||||
} else {
|
||||
if(r == 1) (*calculations)++;
|
||||
if(nsec3_hash_matches_owner(flt, hash, s)) {
|
||||
*rrset = s; /* rrset with this name */
|
||||
*rr = i_rr; /* matches hash with these parameters */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
*rrset = NULL;
|
||||
|
@ -775,6 +816,7 @@ nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash,
|
|||
if(!nsec3_get_nextowner(rrset, rr, &next, &nextlen))
|
||||
return 0; /* malformed RR proves nothing */
|
||||
|
||||
if(!hash) return 0; /* please clang */
|
||||
/* check the owner name is a hashed value . apex
|
||||
* base32 encoded values must have equal length.
|
||||
* hash_value and next hash value must have equal length. */
|
||||
|
@ -823,35 +865,51 @@ nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash,
|
|||
* @param nmlen: length of name.
|
||||
* @param rrset: covering NSEC3 rrset is returned here.
|
||||
* @param rr: rr of cover is returned here.
|
||||
* @param calculations: current hash calculations.
|
||||
* @return true if a covering NSEC3 is found, false if not.
|
||||
*/
|
||||
static int
|
||||
find_covering_nsec3(struct module_env* env, struct nsec3_filter* flt,
|
||||
rbtree_type* ct, uint8_t* nm, size_t nmlen,
|
||||
struct ub_packed_rrset_key** rrset, int* rr)
|
||||
struct nsec3_cache_table* ct, uint8_t* nm, size_t nmlen,
|
||||
struct ub_packed_rrset_key** rrset, int* rr,
|
||||
int* calculations)
|
||||
{
|
||||
size_t i_rs;
|
||||
int i_rr;
|
||||
struct ub_packed_rrset_key* s;
|
||||
struct nsec3_cached_hash* hash = NULL;
|
||||
int r;
|
||||
int calc_errors = 0;
|
||||
|
||||
/* this loop skips other-zone and unknown NSEC3s, also non-NSEC3 RRs */
|
||||
for(s=filter_first(flt, &i_rs, &i_rr); s;
|
||||
s=filter_next(flt, &i_rs, &i_rr)) {
|
||||
/* check if we are allowed more calculations */
|
||||
if(*calculations >= MAX_NSEC3_CALCULATIONS) {
|
||||
if(calc_errors == *calculations) {
|
||||
*calculations = MAX_NSEC3_ERRORS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* get name hashed for this NSEC3 RR */
|
||||
r = nsec3_hash_name(ct, env->scratch, env->scratch_buffer,
|
||||
r = nsec3_hash_name(ct->ct, ct->region, env->scratch_buffer,
|
||||
s, i_rr, nm, nmlen, &hash);
|
||||
if(r == 0) {
|
||||
log_err("nsec3: malloc failure");
|
||||
break; /* alloc failure */
|
||||
} else if(r != 1)
|
||||
continue; /* malformed NSEC3 */
|
||||
else if(nsec3_covers(flt->zone, hash, s, i_rr,
|
||||
env->scratch_buffer)) {
|
||||
*rrset = s; /* rrset with this name */
|
||||
*rr = i_rr; /* covers hash with these parameters */
|
||||
return 1;
|
||||
} else if(r < 0) {
|
||||
/* malformed NSEC3 */
|
||||
calc_errors++;
|
||||
(*calculations)++;
|
||||
continue;
|
||||
} else {
|
||||
if(r == 1) (*calculations)++;
|
||||
if(nsec3_covers(flt->zone, hash, s, i_rr,
|
||||
env->scratch_buffer)) {
|
||||
*rrset = s; /* rrset with this name */
|
||||
*rr = i_rr; /* covers hash with these parameters */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
*rrset = NULL;
|
||||
|
@ -869,11 +927,13 @@ find_covering_nsec3(struct module_env* env, struct nsec3_filter* flt,
|
|||
* @param ct: cached hashes table.
|
||||
* @param qinfo: query that is verified for.
|
||||
* @param ce: closest encloser information is returned in here.
|
||||
* @param calculations: current hash calculations.
|
||||
* @return true if a closest encloser candidate is found, false if not.
|
||||
*/
|
||||
static int
|
||||
nsec3_find_closest_encloser(struct module_env* env, struct nsec3_filter* flt,
|
||||
rbtree_type* ct, struct query_info* qinfo, struct ce_response* ce)
|
||||
struct nsec3_cache_table* ct, struct query_info* qinfo,
|
||||
struct ce_response* ce, int* calculations)
|
||||
{
|
||||
uint8_t* nm = qinfo->qname;
|
||||
size_t nmlen = qinfo->qname_len;
|
||||
|
@ -888,8 +948,12 @@ nsec3_find_closest_encloser(struct module_env* env, struct nsec3_filter* flt,
|
|||
* may be the case. */
|
||||
|
||||
while(dname_subdomain_c(nm, flt->zone)) {
|
||||
if(*calculations >= MAX_NSEC3_CALCULATIONS ||
|
||||
*calculations == MAX_NSEC3_ERRORS) {
|
||||
return 0;
|
||||
}
|
||||
if(find_matching_nsec3(env, flt, ct, nm, nmlen,
|
||||
&ce->ce_rrset, &ce->ce_rr)) {
|
||||
&ce->ce_rrset, &ce->ce_rr, calculations)) {
|
||||
ce->ce = nm;
|
||||
ce->ce_len = nmlen;
|
||||
return 1;
|
||||
|
@ -933,22 +997,38 @@ next_closer(uint8_t* qname, size_t qnamelen, uint8_t* ce,
|
|||
* If set true, and the return value is true, then you can be
|
||||
* certain that the ce.nc_rrset and ce.nc_rr are set properly.
|
||||
* @param ce: closest encloser information is returned in here.
|
||||
* @param calculations: pointer to the current NSEC3 hash calculations.
|
||||
* @return bogus if no closest encloser could be proven.
|
||||
* secure if a closest encloser could be proven, ce is set.
|
||||
* insecure if the closest-encloser candidate turns out to prove
|
||||
* that an insecure delegation exists above the qname.
|
||||
* unchecked if no more hash calculations are allowed at this point.
|
||||
*/
|
||||
static enum sec_status
|
||||
nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt,
|
||||
rbtree_type* ct, struct query_info* qinfo, int prove_does_not_exist,
|
||||
struct ce_response* ce)
|
||||
struct nsec3_cache_table* ct, struct query_info* qinfo,
|
||||
int prove_does_not_exist, struct ce_response* ce, int* calculations)
|
||||
{
|
||||
uint8_t* nc;
|
||||
size_t nc_len;
|
||||
/* robust: clean out ce, in case it gets abused later */
|
||||
memset(ce, 0, sizeof(*ce));
|
||||
|
||||
if(!nsec3_find_closest_encloser(env, flt, ct, qinfo, ce)) {
|
||||
if(!nsec3_find_closest_encloser(env, flt, ct, qinfo, ce, calculations)) {
|
||||
if(*calculations == MAX_NSEC3_ERRORS) {
|
||||
verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could "
|
||||
"not find a candidate for the closest "
|
||||
"encloser; all attempted hash calculations "
|
||||
"were erroneous; bogus");
|
||||
return sec_status_bogus;
|
||||
} else if(*calculations >= MAX_NSEC3_CALCULATIONS) {
|
||||
verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could "
|
||||
"not find a candidate for the closest "
|
||||
"encloser; reached MAX_NSEC3_CALCULATIONS "
|
||||
"(%d); unchecked still",
|
||||
MAX_NSEC3_CALCULATIONS);
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could "
|
||||
"not find a candidate for the closest encloser.");
|
||||
return sec_status_bogus;
|
||||
|
@ -989,9 +1069,23 @@ nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt,
|
|||
/* Otherwise, we need to show that the next closer name is covered. */
|
||||
next_closer(qinfo->qname, qinfo->qname_len, ce->ce, &nc, &nc_len);
|
||||
if(!find_covering_nsec3(env, flt, ct, nc, nc_len,
|
||||
&ce->nc_rrset, &ce->nc_rr)) {
|
||||
&ce->nc_rrset, &ce->nc_rr, calculations)) {
|
||||
if(*calculations == MAX_NSEC3_ERRORS) {
|
||||
verbose(VERB_ALGO, "nsec3: Could not find proof that the "
|
||||
"candidate encloser was the closest encloser; "
|
||||
"all attempted hash calculations were "
|
||||
"erroneous; bogus");
|
||||
return sec_status_bogus;
|
||||
} else if(*calculations >= MAX_NSEC3_CALCULATIONS) {
|
||||
verbose(VERB_ALGO, "nsec3: Could not find proof that the "
|
||||
"candidate encloser was the closest encloser; "
|
||||
"reached MAX_NSEC3_CALCULATIONS (%d); "
|
||||
"unchecked still",
|
||||
MAX_NSEC3_CALCULATIONS);
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
verbose(VERB_ALGO, "nsec3: Could not find proof that the "
|
||||
"candidate encloser was the closest encloser");
|
||||
"candidate encloser was the closest encloser");
|
||||
return sec_status_bogus;
|
||||
}
|
||||
return sec_status_secure;
|
||||
|
@ -1020,7 +1114,7 @@ nsec3_ce_wildcard(struct regional* region, uint8_t* ce, size_t celen,
|
|||
/** Do the name error proof */
|
||||
static enum sec_status
|
||||
nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt,
|
||||
rbtree_type* ct, struct query_info* qinfo)
|
||||
struct nsec3_cache_table* ct, struct query_info* qinfo, int* calc)
|
||||
{
|
||||
struct ce_response ce;
|
||||
uint8_t* wc;
|
||||
|
@ -1032,11 +1126,15 @@ nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt,
|
|||
/* First locate and prove the closest encloser to qname. We will
|
||||
* use the variant that fails if the closest encloser turns out
|
||||
* to be qname. */
|
||||
sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce);
|
||||
sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce, calc);
|
||||
if(sec != sec_status_secure) {
|
||||
if(sec == sec_status_bogus)
|
||||
verbose(VERB_ALGO, "nsec3 nameerror proof: failed "
|
||||
"to prove a closest encloser");
|
||||
else if(sec == sec_status_unchecked)
|
||||
verbose(VERB_ALGO, "nsec3 nameerror proof: will "
|
||||
"continue proving closest encloser after "
|
||||
"suspend");
|
||||
else verbose(VERB_ALGO, "nsec3 nameerror proof: closest "
|
||||
"nsec3 is an insecure delegation");
|
||||
return sec;
|
||||
|
@ -1046,9 +1144,27 @@ nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt,
|
|||
/* At this point, we know that qname does not exist. Now we need
|
||||
* to prove that the wildcard does not exist. */
|
||||
log_assert(ce.ce);
|
||||
wc = nsec3_ce_wildcard(env->scratch, ce.ce, ce.ce_len, &wclen);
|
||||
if(!wc || !find_covering_nsec3(env, flt, ct, wc, wclen,
|
||||
&wc_rrset, &wc_rr)) {
|
||||
wc = nsec3_ce_wildcard(ct->region, ce.ce, ce.ce_len, &wclen);
|
||||
if(!wc) {
|
||||
verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove "
|
||||
"that the applicable wildcard did not exist.");
|
||||
return sec_status_bogus;
|
||||
}
|
||||
if(!find_covering_nsec3(env, flt, ct, wc, wclen, &wc_rrset, &wc_rr, calc)) {
|
||||
if(*calc == MAX_NSEC3_ERRORS) {
|
||||
verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove "
|
||||
"that the applicable wildcard did not exist; "
|
||||
"all attempted hash calculations were "
|
||||
"erroneous; bogus");
|
||||
return sec_status_bogus;
|
||||
} else if(*calc >= MAX_NSEC3_CALCULATIONS) {
|
||||
verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove "
|
||||
"that the applicable wildcard did not exist; "
|
||||
"reached MAX_NSEC3_CALCULATIONS (%d); "
|
||||
"unchecked still",
|
||||
MAX_NSEC3_CALCULATIONS);
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove "
|
||||
"that the applicable wildcard did not exist.");
|
||||
return sec_status_bogus;
|
||||
|
@ -1064,14 +1180,13 @@ nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt,
|
|||
enum sec_status
|
||||
nsec3_prove_nameerror(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)
|
||||
struct query_info* qinfo, struct key_entry_key* kkey,
|
||||
struct nsec3_cache_table* ct, int* calc)
|
||||
{
|
||||
rbtree_type ct;
|
||||
struct nsec3_filter flt;
|
||||
|
||||
if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
|
||||
return sec_status_bogus; /* no valid NSEC3s, bogus */
|
||||
rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
|
||||
filter_init(&flt, list, num, qinfo); /* init RR iterator */
|
||||
if(!flt.zone)
|
||||
return sec_status_bogus; /* no RRs */
|
||||
|
@ -1079,7 +1194,7 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve,
|
|||
return sec_status_insecure; /* iteration count too high */
|
||||
log_nametypeclass(VERB_ALGO, "start nsec3 nameerror proof, zone",
|
||||
flt.zone, 0, 0);
|
||||
return nsec3_do_prove_nameerror(env, &flt, &ct, qinfo);
|
||||
return nsec3_do_prove_nameerror(env, &flt, ct, qinfo, calc);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1090,7 +1205,8 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve,
|
|||
/** Do the nodata proof */
|
||||
static enum sec_status
|
||||
nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt,
|
||||
rbtree_type* ct, struct query_info* qinfo)
|
||||
struct nsec3_cache_table* ct, struct query_info* qinfo,
|
||||
int* calc)
|
||||
{
|
||||
struct ce_response ce;
|
||||
uint8_t* wc;
|
||||
|
@ -1100,7 +1216,7 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt,
|
|||
enum sec_status sec;
|
||||
|
||||
if(find_matching_nsec3(env, flt, ct, qinfo->qname, qinfo->qname_len,
|
||||
&rrset, &rr)) {
|
||||
&rrset, &rr, calc)) {
|
||||
/* cases 1 and 2 */
|
||||
if(nsec3_has_type(rrset, rr, qinfo->qtype)) {
|
||||
verbose(VERB_ALGO, "proveNodata: Matching NSEC3 "
|
||||
|
@ -1144,11 +1260,23 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt,
|
|||
}
|
||||
return sec_status_secure;
|
||||
}
|
||||
if(*calc == MAX_NSEC3_ERRORS) {
|
||||
verbose(VERB_ALGO, "proveNodata: all attempted hash "
|
||||
"calculations were erroneous while finding a matching "
|
||||
"NSEC3, bogus");
|
||||
return sec_status_bogus;
|
||||
} else if(*calc >= MAX_NSEC3_CALCULATIONS) {
|
||||
verbose(VERB_ALGO, "proveNodata: reached "
|
||||
"MAX_NSEC3_CALCULATIONS (%d) while finding a "
|
||||
"matching NSEC3; unchecked still",
|
||||
MAX_NSEC3_CALCULATIONS);
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
|
||||
/* For cases 3 - 5, we need the proven closest encloser, and it
|
||||
* can't match qname. Although, at this point, we know that it
|
||||
* won't since we just checked that. */
|
||||
sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce);
|
||||
sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce, calc);
|
||||
if(sec == sec_status_bogus) {
|
||||
verbose(VERB_ALGO, "proveNodata: did not match qname, "
|
||||
"nor found a proven closest encloser.");
|
||||
|
@ -1157,14 +1285,17 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt,
|
|||
verbose(VERB_ALGO, "proveNodata: closest nsec3 is insecure "
|
||||
"delegation.");
|
||||
return sec_status_insecure;
|
||||
} else if(sec==sec_status_unchecked) {
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
|
||||
/* Case 3: removed */
|
||||
|
||||
/* Case 4: */
|
||||
log_assert(ce.ce);
|
||||
wc = nsec3_ce_wildcard(env->scratch, ce.ce, ce.ce_len, &wclen);
|
||||
if(wc && find_matching_nsec3(env, flt, ct, wc, wclen, &rrset, &rr)) {
|
||||
wc = nsec3_ce_wildcard(ct->region, ce.ce, ce.ce_len, &wclen);
|
||||
if(wc && find_matching_nsec3(env, flt, ct, wc, wclen, &rrset, &rr,
|
||||
calc)) {
|
||||
/* found wildcard */
|
||||
if(nsec3_has_type(rrset, rr, qinfo->qtype)) {
|
||||
verbose(VERB_ALGO, "nsec3 nodata proof: matching "
|
||||
|
@ -1195,6 +1326,18 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt,
|
|||
}
|
||||
return sec_status_secure;
|
||||
}
|
||||
if(*calc == MAX_NSEC3_ERRORS) {
|
||||
verbose(VERB_ALGO, "nsec3 nodata proof: all attempted hash "
|
||||
"calculations were erroneous while matching "
|
||||
"wildcard, bogus");
|
||||
return sec_status_bogus;
|
||||
} else if(*calc >= MAX_NSEC3_CALCULATIONS) {
|
||||
verbose(VERB_ALGO, "nsec3 nodata proof: reached "
|
||||
"MAX_NSEC3_CALCULATIONS (%d) while matching "
|
||||
"wildcard, unchecked still",
|
||||
MAX_NSEC3_CALCULATIONS);
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
|
||||
/* Case 5: */
|
||||
/* Due to forwarders, cnames, and other collating effects, we
|
||||
|
@ -1223,28 +1366,27 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt,
|
|||
enum sec_status
|
||||
nsec3_prove_nodata(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)
|
||||
struct query_info* qinfo, struct key_entry_key* kkey,
|
||||
struct nsec3_cache_table* ct, int* calc)
|
||||
{
|
||||
rbtree_type ct;
|
||||
struct nsec3_filter flt;
|
||||
|
||||
if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
|
||||
return sec_status_bogus; /* no valid NSEC3s, bogus */
|
||||
rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
|
||||
filter_init(&flt, list, num, qinfo); /* init RR iterator */
|
||||
if(!flt.zone)
|
||||
return sec_status_bogus; /* no RRs */
|
||||
if(nsec3_iteration_count_high(ve, &flt, kkey))
|
||||
return sec_status_insecure; /* iteration count too high */
|
||||
return nsec3_do_prove_nodata(env, &flt, &ct, qinfo);
|
||||
return nsec3_do_prove_nodata(env, &flt, ct, qinfo, calc);
|
||||
}
|
||||
|
||||
enum sec_status
|
||||
nsec3_prove_wildcard(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, uint8_t* wc)
|
||||
struct query_info* qinfo, struct key_entry_key* kkey, uint8_t* wc,
|
||||
struct nsec3_cache_table* ct, int* calc)
|
||||
{
|
||||
rbtree_type ct;
|
||||
struct nsec3_filter flt;
|
||||
struct ce_response ce;
|
||||
uint8_t* nc;
|
||||
|
@ -1254,7 +1396,6 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve,
|
|||
|
||||
if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
|
||||
return sec_status_bogus; /* no valid NSEC3s, bogus */
|
||||
rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
|
||||
filter_init(&flt, list, num, qinfo); /* init RR iterator */
|
||||
if(!flt.zone)
|
||||
return sec_status_bogus; /* no RRs */
|
||||
|
@ -1272,8 +1413,22 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve,
|
|||
/* Now we still need to prove that the original data did not exist.
|
||||
* Otherwise, we need to show that the next closer name is covered. */
|
||||
next_closer(qinfo->qname, qinfo->qname_len, ce.ce, &nc, &nc_len);
|
||||
if(!find_covering_nsec3(env, &flt, &ct, nc, nc_len,
|
||||
&ce.nc_rrset, &ce.nc_rr)) {
|
||||
if(!find_covering_nsec3(env, &flt, ct, nc, nc_len,
|
||||
&ce.nc_rrset, &ce.nc_rr, calc)) {
|
||||
if(*calc == MAX_NSEC3_ERRORS) {
|
||||
verbose(VERB_ALGO, "proveWildcard: did not find a "
|
||||
"covering NSEC3 that covered the next closer "
|
||||
"name; all attempted hash calculations were "
|
||||
"erroneous; bogus");
|
||||
return sec_status_bogus;
|
||||
} else if(*calc >= MAX_NSEC3_CALCULATIONS) {
|
||||
verbose(VERB_ALGO, "proveWildcard: did not find a "
|
||||
"covering NSEC3 that covered the next closer "
|
||||
"name; reached MAX_NSEC3_CALCULATIONS "
|
||||
"(%d); unchecked still",
|
||||
MAX_NSEC3_CALCULATIONS);
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
verbose(VERB_ALGO, "proveWildcard: did not find a covering "
|
||||
"NSEC3 that covered the next closer name.");
|
||||
return sec_status_bogus;
|
||||
|
@ -1294,6 +1449,7 @@ list_is_secure(struct module_env* env, struct val_env* ve,
|
|||
{
|
||||
struct packed_rrset_data* d;
|
||||
size_t i;
|
||||
int verified = 0;
|
||||
for(i=0; i<num; i++) {
|
||||
d = (struct packed_rrset_data*)list[i]->entry.data;
|
||||
if(list[i]->rk.type != htons(LDNS_RR_TYPE_NSEC3))
|
||||
|
@ -1304,7 +1460,8 @@ list_is_secure(struct module_env* env, struct val_env* ve,
|
|||
if(d->security == sec_status_secure)
|
||||
continue;
|
||||
d->security = val_verify_rrset_entry(env, ve, list[i], kkey,
|
||||
reason, reason_bogus, LDNS_SECTION_AUTHORITY, qstate);
|
||||
reason, reason_bogus, LDNS_SECTION_AUTHORITY, qstate,
|
||||
&verified);
|
||||
if(d->security != sec_status_secure) {
|
||||
verbose(VERB_ALGO, "NSEC3 did not verify");
|
||||
return 0;
|
||||
|
@ -1318,13 +1475,16 @@ enum sec_status
|
|||
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)
|
||||
sldns_ede_code* reason_bogus, struct module_qstate* qstate,
|
||||
struct nsec3_cache_table* ct)
|
||||
{
|
||||
rbtree_type ct;
|
||||
struct nsec3_filter flt;
|
||||
struct ce_response ce;
|
||||
struct ub_packed_rrset_key* rrset;
|
||||
int rr;
|
||||
int calc = 0;
|
||||
enum sec_status sec;
|
||||
|
||||
log_assert(qinfo->qtype == LDNS_RR_TYPE_DS);
|
||||
|
||||
if(!list || num == 0 || !kkey || !key_entry_isgood(kkey)) {
|
||||
|
@ -1335,7 +1495,6 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
|
|||
*reason = "not all NSEC3 records secure";
|
||||
return sec_status_bogus; /* not all NSEC3 records secure */
|
||||
}
|
||||
rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
|
||||
filter_init(&flt, list, num, qinfo); /* init RR iterator */
|
||||
if(!flt.zone) {
|
||||
*reason = "no NSEC3 records";
|
||||
|
@ -1346,8 +1505,8 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
|
|||
|
||||
/* Look for a matching NSEC3 to qname -- this is the normal
|
||||
* NODATA case. */
|
||||
if(find_matching_nsec3(env, &flt, &ct, qinfo->qname, qinfo->qname_len,
|
||||
&rrset, &rr)) {
|
||||
if(find_matching_nsec3(env, &flt, ct, qinfo->qname, qinfo->qname_len,
|
||||
&rrset, &rr, &calc)) {
|
||||
/* If the matching NSEC3 has the SOA bit set, it is from
|
||||
* the wrong zone (the child instead of the parent). If
|
||||
* it has the DS bit set, then we were lied to. */
|
||||
|
@ -1370,10 +1529,24 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
|
|||
/* Otherwise, this proves no DS. */
|
||||
return sec_status_secure;
|
||||
}
|
||||
if(calc == MAX_NSEC3_ERRORS) {
|
||||
verbose(VERB_ALGO, "nsec3 provenods: all attempted hash "
|
||||
"calculations were erroneous while finding a matching "
|
||||
"NSEC3, bogus");
|
||||
return sec_status_bogus;
|
||||
} else if(calc >= MAX_NSEC3_CALCULATIONS) {
|
||||
verbose(VERB_ALGO, "nsec3 provenods: reached "
|
||||
"MAX_NSEC3_CALCULATIONS (%d) while finding a "
|
||||
"matching NSEC3, unchecked still",
|
||||
MAX_NSEC3_CALCULATIONS);
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
|
||||
/* Otherwise, we are probably in the opt-out case. */
|
||||
if(nsec3_prove_closest_encloser(env, &flt, &ct, qinfo, 1, &ce)
|
||||
!= sec_status_secure) {
|
||||
sec = nsec3_prove_closest_encloser(env, &flt, ct, qinfo, 1, &ce, &calc);
|
||||
if(sec == sec_status_unchecked) {
|
||||
return sec_status_unchecked;
|
||||
} else if(sec != sec_status_secure) {
|
||||
/* an insecure delegation *above* the qname does not prove
|
||||
* anything about this qname exactly, and bogus is bogus */
|
||||
verbose(VERB_ALGO, "nsec3 provenods: did not match qname, "
|
||||
|
@ -1408,16 +1581,15 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
|
|||
enum sec_status
|
||||
nsec3_prove_nxornodata(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, int* nodata)
|
||||
struct query_info* qinfo, struct key_entry_key* kkey, int* nodata,
|
||||
struct nsec3_cache_table* ct, int* calc)
|
||||
{
|
||||
enum sec_status sec, secnx;
|
||||
rbtree_type ct;
|
||||
struct nsec3_filter flt;
|
||||
*nodata = 0;
|
||||
|
||||
if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
|
||||
return sec_status_bogus; /* no valid NSEC3s, bogus */
|
||||
rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
|
||||
filter_init(&flt, list, num, qinfo); /* init RR iterator */
|
||||
if(!flt.zone)
|
||||
return sec_status_bogus; /* no RRs */
|
||||
|
@ -1427,16 +1599,20 @@ nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve,
|
|||
/* try nxdomain and nodata after another, while keeping the
|
||||
* hash cache intact */
|
||||
|
||||
secnx = nsec3_do_prove_nameerror(env, &flt, &ct, qinfo);
|
||||
secnx = nsec3_do_prove_nameerror(env, &flt, ct, qinfo, calc);
|
||||
if(secnx==sec_status_secure)
|
||||
return sec_status_secure;
|
||||
sec = nsec3_do_prove_nodata(env, &flt, &ct, qinfo);
|
||||
else if(secnx == sec_status_unchecked)
|
||||
return sec_status_unchecked;
|
||||
sec = nsec3_do_prove_nodata(env, &flt, ct, qinfo, calc);
|
||||
if(sec==sec_status_secure) {
|
||||
*nodata = 1;
|
||||
} else if(sec == sec_status_insecure) {
|
||||
*nodata = 1;
|
||||
} else if(secnx == sec_status_insecure) {
|
||||
sec = sec_status_insecure;
|
||||
} else if(sec == sec_status_unchecked) {
|
||||
return sec_status_unchecked;
|
||||
}
|
||||
return sec;
|
||||
}
|
||||
|
|
|
@ -98,6 +98,15 @@ struct sldns_buffer;
|
|||
/** The SHA1 hash algorithm for NSEC3 */
|
||||
#define NSEC3_HASH_SHA1 0x01
|
||||
|
||||
/**
|
||||
* Cache table for NSEC3 hashes.
|
||||
* It keeps a *pointer* to the region its items are allocated.
|
||||
*/
|
||||
struct nsec3_cache_table {
|
||||
rbtree_type* ct;
|
||||
struct regional* region;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine if the set of NSEC3 records provided with a response prove NAME
|
||||
* ERROR. This means that the NSEC3s prove a) the closest encloser exists,
|
||||
|
@ -110,14 +119,18 @@ struct sldns_buffer;
|
|||
* @param num: number of RRsets in the array to examine.
|
||||
* @param qinfo: query that is verified for.
|
||||
* @param kkey: key entry that signed the NSEC3s.
|
||||
* @param ct: cached hashes table.
|
||||
* @param calc: current hash calculations.
|
||||
* @return:
|
||||
* sec_status SECURE of the Name Error is proven by the NSEC3 RRs,
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored,
|
||||
* UNCHECKED if no more hash calculations are allowed at this point.
|
||||
*/
|
||||
enum sec_status
|
||||
nsec3_prove_nameerror(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);
|
||||
struct query_info* qinfo, struct key_entry_key* kkey,
|
||||
struct nsec3_cache_table* ct, int* calc);
|
||||
|
||||
/**
|
||||
* Determine if the NSEC3s provided in a response prove the NOERROR/NODATA
|
||||
|
@ -144,15 +157,18 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve,
|
|||
* @param num: number of RRsets in the array to examine.
|
||||
* @param qinfo: query that is verified for.
|
||||
* @param kkey: key entry that signed the NSEC3s.
|
||||
* @param ct: cached hashes table.
|
||||
* @param calc: current hash calculations.
|
||||
* @return:
|
||||
* sec_status SECURE of the proposition is proven by the NSEC3 RRs,
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored,
|
||||
* UNCHECKED if no more hash calculations are allowed at this point.
|
||||
*/
|
||||
enum sec_status
|
||||
nsec3_prove_nodata(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);
|
||||
|
||||
struct query_info* qinfo, struct key_entry_key* kkey,
|
||||
struct nsec3_cache_table* ct, int* calc);
|
||||
|
||||
/**
|
||||
* Prove that a positive wildcard match was appropriate (no direct match
|
||||
|
@ -166,14 +182,18 @@ nsec3_prove_nodata(struct module_env* env, struct val_env* ve,
|
|||
* @param kkey: key entry that signed the NSEC3s.
|
||||
* @param wc: The purported wildcard that matched. This is the wildcard name
|
||||
* as *.wildcard.name., with the *. label already removed.
|
||||
* @param ct: cached hashes table.
|
||||
* @param calc: current hash calculations.
|
||||
* @return:
|
||||
* sec_status SECURE of the proposition is proven by the NSEC3 RRs,
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored,
|
||||
* UNCHECKED if no more hash calculations are allowed at this point.
|
||||
*/
|
||||
enum sec_status
|
||||
nsec3_prove_wildcard(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, uint8_t* wc);
|
||||
struct query_info* qinfo, struct key_entry_key* kkey, uint8_t* wc,
|
||||
struct nsec3_cache_table* ct, int* calc);
|
||||
|
||||
/**
|
||||
* Prove that a DS response either had no DS, or wasn't a delegation point.
|
||||
|
@ -189,17 +209,20 @@ 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 ct: cached hashes table.
|
||||
* @return:
|
||||
* sec_status SECURE of the proposition is proven by the NSEC3 RRs,
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
|
||||
* or if there was no DS in an insecure (i.e., opt-in) way,
|
||||
* INDETERMINATE if it was clear that this wasn't a delegation point.
|
||||
* INDETERMINATE if it was clear that this wasn't a delegation point,
|
||||
* UNCHECKED if no more hash calculations are allowed at this point.
|
||||
*/
|
||||
enum sec_status
|
||||
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);
|
||||
sldns_ede_code* reason_bogus, struct module_qstate* qstate,
|
||||
struct nsec3_cache_table* ct);
|
||||
|
||||
/**
|
||||
* Prove NXDOMAIN or NODATA.
|
||||
|
@ -212,14 +235,18 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
|
|||
* @param kkey: key entry that signed the NSEC3s.
|
||||
* @param nodata: if return value is secure, this indicates if nodata or
|
||||
* nxdomain was proven.
|
||||
* @param ct: cached hashes table.
|
||||
* @param calc: current hash calculations.
|
||||
* @return:
|
||||
* sec_status SECURE of the proposition is proven by the NSEC3 RRs,
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
|
||||
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored,
|
||||
* UNCHECKED if no more hash calculations are allowed at this point.
|
||||
*/
|
||||
enum sec_status
|
||||
nsec3_prove_nxornodata(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, int* nodata);
|
||||
struct query_info* qinfo, struct key_entry_key* kkey, int* nodata,
|
||||
struct nsec3_cache_table* ct, int* calc);
|
||||
|
||||
/**
|
||||
* The NSEC3 hash result storage.
|
||||
|
@ -256,6 +283,14 @@ struct nsec3_cached_hash {
|
|||
*/
|
||||
int nsec3_hash_cmp(const void* c1, const void* c2);
|
||||
|
||||
/**
|
||||
* Initialise the NSEC3 cache table.
|
||||
* @param ct: the nsec3 cache table.
|
||||
* @param region: the region where allocations for the table will happen.
|
||||
* @return true on success, false on malloc error.
|
||||
*/
|
||||
int nsec3_cache_table_init(struct nsec3_cache_table* ct, struct regional* region);
|
||||
|
||||
/**
|
||||
* Obtain the hash of an owner name.
|
||||
* Used internally by the nsec3 proof functions in this file.
|
||||
|
@ -272,7 +307,8 @@ int nsec3_hash_cmp(const void* c1, const void* c2);
|
|||
* @param dname_len: the length of the name.
|
||||
* @param hash: the hash node is returned on success.
|
||||
* @return:
|
||||
* 1 on success, either from cache or newly hashed hash is returned.
|
||||
* 2 on success, hash from cache is returned.
|
||||
* 1 on success, newly computed hash is returned.
|
||||
* 0 on a malloc failure.
|
||||
* -1 if the NSEC3 rr was badly formatted (i.e. formerr).
|
||||
*/
|
||||
|
|
|
@ -79,6 +79,9 @@
|
|||
#include <openssl/engine.h>
|
||||
#endif
|
||||
|
||||
/** Maximum number of RRSIG validations for an RRset. */
|
||||
#define MAX_VALIDATE_RRSIGS 8
|
||||
|
||||
/** return number of rrs in an rrset */
|
||||
static size_t
|
||||
rrset_get_count(struct ub_packed_rrset_key* rrset)
|
||||
|
@ -542,6 +545,8 @@ 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 numverified: incremented when the number of RRSIG validations
|
||||
* increases.
|
||||
* @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).
|
||||
|
@ -552,7 +557,8 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
|
|||
struct ub_packed_rrset_key* dnskey, size_t sig_idx,
|
||||
struct rbtree_type** sortree,
|
||||
char** reason, sldns_ede_code *reason_bogus,
|
||||
sldns_pkt_section section, struct module_qstate* qstate)
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
int* numverified)
|
||||
{
|
||||
/* find matching keys and check them */
|
||||
enum sec_status sec = sec_status_bogus;
|
||||
|
@ -576,6 +582,7 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
|
|||
tag != dnskey_calc_keytag(dnskey, i))
|
||||
continue;
|
||||
numchecked ++;
|
||||
(*numverified)++;
|
||||
|
||||
/* see if key verifies */
|
||||
sec = dnskey_verify_rrset_sig(env->scratch,
|
||||
|
@ -586,6 +593,13 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve,
|
|||
return sec;
|
||||
else if(sec == sec_status_indeterminate)
|
||||
numindeterminate ++;
|
||||
if(*numverified > MAX_VALIDATE_RRSIGS) {
|
||||
*reason = "too many RRSIG validations";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
verbose(VERB_ALGO, "verify sig: too many RRSIG validations");
|
||||
return sec_status_bogus;
|
||||
}
|
||||
}
|
||||
if(numchecked == 0) {
|
||||
*reason = "signatures from unknown keys";
|
||||
|
@ -609,7 +623,7 @@ 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)
|
||||
sldns_pkt_section section, struct module_qstate* qstate, int* verified)
|
||||
{
|
||||
enum sec_status sec;
|
||||
size_t i, num;
|
||||
|
@ -617,6 +631,7 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
/* make sure that for all DNSKEY algorithms there are valid sigs */
|
||||
struct algo_needs needs;
|
||||
int alg;
|
||||
*verified = 0;
|
||||
|
||||
num = rrset_get_sigcount(rrset);
|
||||
if(num == 0) {
|
||||
|
@ -641,7 +656,7 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
for(i=0; i<num; i++) {
|
||||
sec = dnskeyset_verify_rrset_sig(env, ve, *env->now, rrset,
|
||||
dnskey, i, &sortree, reason, reason_bogus,
|
||||
section, qstate);
|
||||
section, qstate, verified);
|
||||
/* see which algorithm has been fixed up */
|
||||
if(sec == sec_status_secure) {
|
||||
if(!sigalg)
|
||||
|
@ -653,6 +668,13 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
algo_needs_set_bogus(&needs,
|
||||
(uint8_t)rrset_get_sig_algo(rrset, i));
|
||||
}
|
||||
if(*verified > MAX_VALIDATE_RRSIGS) {
|
||||
verbose(VERB_QUERY, "rrset failed to verify, too many RRSIG validations");
|
||||
*reason = "too many RRSIG validations";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
return sec_status_bogus;
|
||||
}
|
||||
}
|
||||
if(sigalg && (alg=algo_needs_missing(&needs)) != 0) {
|
||||
verbose(VERB_ALGO, "rrset failed to verify: "
|
||||
|
@ -691,6 +713,7 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
int buf_canon = 0;
|
||||
uint16_t tag = dnskey_calc_keytag(dnskey, dnskey_idx);
|
||||
int algo = dnskey_get_algo(dnskey, dnskey_idx);
|
||||
int numverified = 0;
|
||||
|
||||
num = rrset_get_sigcount(rrset);
|
||||
if(num == 0) {
|
||||
|
@ -714,8 +737,16 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
if(sec == sec_status_secure)
|
||||
return sec;
|
||||
numchecked ++;
|
||||
numverified ++;
|
||||
if(sec == sec_status_indeterminate)
|
||||
numindeterminate ++;
|
||||
if(numverified > MAX_VALIDATE_RRSIGS) {
|
||||
verbose(VERB_QUERY, "rrset failed to verify, too many RRSIG validations");
|
||||
*reason = "too many RRSIG validations";
|
||||
if(reason_bogus)
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
return sec_status_bogus;
|
||||
}
|
||||
}
|
||||
verbose(VERB_ALGO, "rrset failed to verify: all signatures are bogus");
|
||||
if(!numchecked) {
|
||||
|
|
|
@ -260,6 +260,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 verified: if not NULL the number of RRSIG validations is returned.
|
||||
* @return SECURE if one key in the set verifies one rrsig.
|
||||
* UNCHECKED on allocation errors, unsupported algorithms, malformed data,
|
||||
* and BOGUS on verification failures (no keys match any signatures).
|
||||
|
@ -268,7 +269,7 @@ 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);
|
||||
sldns_pkt_section section, struct module_qstate* qstate, int* verified);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -58,6 +58,10 @@
|
|||
#include "sldns/wire2str.h"
|
||||
#include "sldns/parseutil.h"
|
||||
|
||||
/** Maximum allowed digest match failures per DS, for DNSKEYs with the same
|
||||
* properties */
|
||||
#define MAX_DS_MATCH_FAILURES 4
|
||||
|
||||
enum val_classification
|
||||
val_classify_response(uint16_t query_flags, struct query_info* origqinf,
|
||||
struct query_info* qinf, struct reply_info* rep, size_t skip)
|
||||
|
@ -336,7 +340,8 @@ static enum sec_status
|
|||
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)
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
int *verified)
|
||||
{
|
||||
enum sec_status sec;
|
||||
struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
|
||||
|
@ -346,6 +351,7 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
log_nametypeclass(VERB_ALGO, "verify rrset cached",
|
||||
rrset->rk.dname, ntohs(rrset->rk.type),
|
||||
ntohs(rrset->rk.rrset_class));
|
||||
*verified = 0;
|
||||
return d->security;
|
||||
}
|
||||
/* check in the cache if verification has already been done */
|
||||
|
@ -354,12 +360,13 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
|
|||
log_nametypeclass(VERB_ALGO, "verify rrset from cache",
|
||||
rrset->rk.dname, ntohs(rrset->rk.type),
|
||||
ntohs(rrset->rk.rrset_class));
|
||||
*verified = 0;
|
||||
return d->security;
|
||||
}
|
||||
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);
|
||||
reason_bogus, section, qstate, verified);
|
||||
verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec));
|
||||
regional_free_all(env->scratch);
|
||||
|
||||
|
@ -393,7 +400,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)
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
int* verified)
|
||||
{
|
||||
/* temporary dnskey rrset-key */
|
||||
struct ub_packed_rrset_key dnskey;
|
||||
|
@ -407,7 +415,7 @@ 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);
|
||||
reason_bogus, section, qstate, verified);
|
||||
return sec;
|
||||
}
|
||||
|
||||
|
@ -439,6 +447,12 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
|
|||
if(!ds_digest_match_dnskey(env, dnskey_rrset, i, ds_rrset,
|
||||
ds_idx)) {
|
||||
verbose(VERB_ALGO, "DS match attempt failed");
|
||||
if(numchecked > numhashok + MAX_DS_MATCH_FAILURES) {
|
||||
verbose(VERB_ALGO, "DS match attempt reached "
|
||||
"MAX_DS_MATCH_FAILURES (%d); bogus",
|
||||
MAX_DS_MATCH_FAILURES);
|
||||
return sec_status_bogus;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
numhashok++;
|
||||
|
|
|
@ -124,12 +124,14 @@ 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 verified: if not NULL, the number of RRSIG validations is returned.
|
||||
* @return security status of verification.
|
||||
*/
|
||||
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);
|
||||
sldns_pkt_section section, struct module_qstate* qstate,
|
||||
int* verified);
|
||||
|
||||
/**
|
||||
* Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but
|
||||
|
|
|
@ -64,10 +64,15 @@
|
|||
#include "sldns/wire2str.h"
|
||||
#include "sldns/str2wire.h"
|
||||
|
||||
/** Max number of RRSIGs to validate at once, suspend query for later. */
|
||||
#define MAX_VALIDATE_AT_ONCE 8
|
||||
/** Max number of validation suspends allowed, error out otherwise. */
|
||||
#define MAX_VALIDATION_SUSPENDS 16
|
||||
|
||||
/* forward decl for cache response and normal super inform calls of a DS */
|
||||
static void process_ds_response(struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int id, int rcode, struct dns_msg* msg,
|
||||
struct query_info* qinfo, struct sock_list* origin);
|
||||
struct query_info* qinfo, struct sock_list* origin, int* suspend);
|
||||
|
||||
|
||||
/* Updates the suplied EDE (RFC8914) code selectively so we don't lose
|
||||
|
@ -281,6 +286,21 @@ val_new(struct module_qstate* qstate, int id)
|
|||
return val_new_getmsg(qstate, vq);
|
||||
}
|
||||
|
||||
/** reset validator query state for query restart */
|
||||
static void
|
||||
val_restart(struct val_qstate* vq)
|
||||
{
|
||||
struct comm_timer* temp_timer;
|
||||
int restart_count;
|
||||
if(!vq) return;
|
||||
temp_timer = vq->suspend_timer;
|
||||
restart_count = vq->restart_count+1;
|
||||
memset(vq, 0, sizeof(*vq));
|
||||
vq->suspend_timer = temp_timer;
|
||||
vq->restart_count = restart_count;
|
||||
vq->state = VAL_INIT_STATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit validation with an error status
|
||||
*
|
||||
|
@ -587,30 +607,42 @@ prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
* completed.
|
||||
*
|
||||
* @param qstate: query state.
|
||||
* @param vq: validator query state.
|
||||
* @param env: module env for verify.
|
||||
* @param ve: validator env for verify.
|
||||
* @param qchase: query that was made.
|
||||
* @param chase_reply: answer to validate.
|
||||
* @param key_entry: the key entry, which is trusted, and which matches
|
||||
* the signer of the answer. The key entry isgood().
|
||||
* @param suspend: returned true if the task takes too long and needs to
|
||||
* suspend to continue the effort later.
|
||||
* @return false if any of the rrsets in the an or ns sections of the message
|
||||
* fail to verify. The message is then set to bogus.
|
||||
*/
|
||||
static int
|
||||
validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
|
||||
struct val_env* ve, struct query_info* qchase,
|
||||
struct reply_info* chase_reply, struct key_entry_key* key_entry)
|
||||
validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
struct module_env* env, struct val_env* ve, struct query_info* qchase,
|
||||
struct reply_info* chase_reply, struct key_entry_key* key_entry,
|
||||
int* suspend)
|
||||
{
|
||||
uint8_t* sname;
|
||||
size_t i, slen;
|
||||
struct ub_packed_rrset_key* s;
|
||||
enum sec_status sec;
|
||||
int dname_seen = 0;
|
||||
int dname_seen = 0, num_verifies = 0, verified, have_state = 0;
|
||||
char* reason = NULL;
|
||||
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
*suspend = 0;
|
||||
if(vq->msg_signatures_state) {
|
||||
/* Pick up the state, and reset it, may not be needed now. */
|
||||
vq->msg_signatures_state = 0;
|
||||
have_state = 1;
|
||||
}
|
||||
|
||||
/* validate the ANSWER section */
|
||||
for(i=0; i<chase_reply->an_numrrsets; i++) {
|
||||
if(have_state && i <= vq->msg_signatures_index)
|
||||
continue;
|
||||
s = chase_reply->rrsets[i];
|
||||
/* Skip the CNAME following a (validated) DNAME.
|
||||
* Because of the normalization routines in the iterator,
|
||||
|
@ -629,7 +661,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
|
|||
|
||||
/* Verify the answer rrset */
|
||||
sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
|
||||
&reason_bogus, LDNS_SECTION_ANSWER, qstate);
|
||||
&reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified);
|
||||
/* If the (answer) rrset failed to validate, then this
|
||||
* message is BAD. */
|
||||
if(sec != sec_status_secure) {
|
||||
|
@ -654,14 +686,33 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
|
|||
ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME) {
|
||||
dname_seen = 1;
|
||||
}
|
||||
num_verifies += verified;
|
||||
if(num_verifies > MAX_VALIDATE_AT_ONCE &&
|
||||
i+1 < (env->cfg->val_clean_additional?
|
||||
chase_reply->an_numrrsets+chase_reply->ns_numrrsets:
|
||||
chase_reply->rrset_count)) {
|
||||
/* If the number of RRSIGs exceeds the maximum in
|
||||
* one go, suspend. Only suspend if there is a next
|
||||
* rrset to verify, i+1<loopmax. Store where to
|
||||
* continue later. */
|
||||
*suspend = 1;
|
||||
vq->msg_signatures_state = 1;
|
||||
vq->msg_signatures_index = i;
|
||||
verbose(VERB_ALGO, "msg signature validation "
|
||||
"suspended");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* validate the AUTHORITY section */
|
||||
for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
|
||||
chase_reply->ns_numrrsets; i++) {
|
||||
if(have_state && i <= vq->msg_signatures_index)
|
||||
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,
|
||||
&verified);
|
||||
/* If anything in the authority section fails to be secure,
|
||||
* we have a bad message. */
|
||||
if(sec != sec_status_secure) {
|
||||
|
@ -675,6 +726,18 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
|
|||
update_reason_bogus(chase_reply, reason_bogus);
|
||||
return 0;
|
||||
}
|
||||
num_verifies += verified;
|
||||
if(num_verifies > MAX_VALIDATE_AT_ONCE &&
|
||||
i+1 < (env->cfg->val_clean_additional?
|
||||
chase_reply->an_numrrsets+chase_reply->ns_numrrsets:
|
||||
chase_reply->rrset_count)) {
|
||||
*suspend = 1;
|
||||
vq->msg_signatures_state = 1;
|
||||
vq->msg_signatures_index = i;
|
||||
verbose(VERB_ALGO, "msg signature validation "
|
||||
"suspended");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If set, the validator should clean the additional section of
|
||||
|
@ -684,22 +747,103 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env,
|
|||
/* attempt to validate the ADDITIONAL section rrsets */
|
||||
for(i=chase_reply->an_numrrsets+chase_reply->ns_numrrsets;
|
||||
i<chase_reply->rrset_count; i++) {
|
||||
if(have_state && i <= vq->msg_signatures_index)
|
||||
continue;
|
||||
s = chase_reply->rrsets[i];
|
||||
/* only validate rrs that have signatures with the key */
|
||||
/* leave others unchecked, those get removed later on too */
|
||||
val_find_rrset_signer(s, &sname, &slen);
|
||||
|
||||
verified = 0;
|
||||
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);
|
||||
&reason, NULL, LDNS_SECTION_ADDITIONAL, qstate,
|
||||
&verified);
|
||||
/* the additional section can fail to be secure,
|
||||
* it is optional, check signature in case we need
|
||||
* to clean the additional section later. */
|
||||
num_verifies += verified;
|
||||
if(num_verifies > MAX_VALIDATE_AT_ONCE &&
|
||||
i+1 < chase_reply->rrset_count) {
|
||||
*suspend = 1;
|
||||
vq->msg_signatures_state = 1;
|
||||
vq->msg_signatures_index = i;
|
||||
verbose(VERB_ALGO, "msg signature validation "
|
||||
"suspended");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
validate_suspend_timer_cb(void* arg)
|
||||
{
|
||||
struct module_qstate* qstate = (struct module_qstate*)arg;
|
||||
verbose(VERB_ALGO, "validate_suspend timer, continue");
|
||||
mesh_run(qstate->env->mesh, qstate->mesh_info, module_event_pass,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/** Setup timer to continue validation of msg signatures later */
|
||||
static int
|
||||
validate_suspend_setup_timer(struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int id, enum val_state resume_state)
|
||||
{
|
||||
struct timeval tv;
|
||||
int usec, slack, base;
|
||||
if(vq->suspend_count >= MAX_VALIDATION_SUSPENDS) {
|
||||
verbose(VERB_ALGO, "validate_suspend timer: "
|
||||
"reached MAX_VALIDATION_SUSPENDS (%d); error out",
|
||||
MAX_VALIDATION_SUSPENDS);
|
||||
errinf(qstate, "max validation suspends reached, "
|
||||
"too many RRSIG validations");
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "validate_suspend timer, set for suspend");
|
||||
vq->state = resume_state;
|
||||
qstate->ext_state[id] = module_wait_reply;
|
||||
if(!vq->suspend_timer) {
|
||||
vq->suspend_timer = comm_timer_create(
|
||||
qstate->env->worker_base,
|
||||
validate_suspend_timer_cb, qstate);
|
||||
if(!vq->suspend_timer) {
|
||||
log_err("validate_suspend_setup_timer: "
|
||||
"out of memory for comm_timer_create");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* The timer is activated later, after other events in the event
|
||||
* loop have been processed. The query state can also be deleted,
|
||||
* when the list is full and query states are dropped. */
|
||||
/* Extend wait time if there are a lot of queries or if this one
|
||||
* is taking long, to keep around cpu time for ordinary queries. */
|
||||
usec = 50000; /* 50 msec */
|
||||
slack = 0;
|
||||
if(qstate->env->mesh->all.count >= qstate->env->mesh->max_reply_states)
|
||||
slack += 3;
|
||||
else if(qstate->env->mesh->all.count >= qstate->env->mesh->max_reply_states/2)
|
||||
slack += 2;
|
||||
else if(qstate->env->mesh->all.count >= qstate->env->mesh->max_reply_states/4)
|
||||
slack += 1;
|
||||
if(vq->suspend_count > 3)
|
||||
slack += 3;
|
||||
else if(vq->suspend_count > 0)
|
||||
slack += vq->suspend_count;
|
||||
if(slack != 0 && slack <= 12 /* No numeric overflow. */) {
|
||||
usec = usec << slack;
|
||||
}
|
||||
/* Spread such timeouts within 90%-100% of the original timer. */
|
||||
base = usec * 9/10;
|
||||
usec = base + ub_random_max(qstate->env->rnd, usec-base);
|
||||
tv.tv_usec = (usec % 1000000);
|
||||
tv.tv_sec = (usec / 1000000);
|
||||
vq->suspend_count ++;
|
||||
comm_timer_set(vq->suspend_timer, &tv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect wrong truncated response (say from BIND 9.6.1 that is forwarding
|
||||
* and saw the NS record without signatures from a referral).
|
||||
|
@ -798,11 +942,17 @@ remove_spurious_authority(struct reply_info* chase_reply,
|
|||
* @param chase_reply: answer to that query to validate.
|
||||
* @param kkey: the key entry, which is trusted, and which matches
|
||||
* the signer of the answer. The key entry isgood().
|
||||
* @param qstate: query state for the region.
|
||||
* @param vq: validator state for the nsec3 cache table.
|
||||
* @param nsec3_calculations: current nsec3 hash calculations.
|
||||
* @param suspend: returned true if the task takes too long and needs to
|
||||
* suspend to continue the effort later.
|
||||
*/
|
||||
static void
|
||||
validate_positive_response(struct module_env* env, struct val_env* ve,
|
||||
struct query_info* qchase, struct reply_info* chase_reply,
|
||||
struct key_entry_key* kkey)
|
||||
struct key_entry_key* kkey, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int* nsec3_calculations, int* suspend)
|
||||
{
|
||||
uint8_t* wc = NULL;
|
||||
size_t wl;
|
||||
|
@ -811,6 +961,7 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
|
|||
int nsec3s_seen = 0;
|
||||
size_t i;
|
||||
struct ub_packed_rrset_key* s;
|
||||
*suspend = 0;
|
||||
|
||||
/* validate the ANSWER section - this will be the answer itself */
|
||||
for(i=0; i<chase_reply->an_numrrsets; i++) {
|
||||
|
@ -862,17 +1013,23 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
|
|||
/* If this was a positive wildcard response that we haven't already
|
||||
* proven, and we have NSEC3 records, try to prove it using the NSEC3
|
||||
* records. */
|
||||
if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) {
|
||||
if(wc != NULL && !wc_NSEC_ok && nsec3s_seen &&
|
||||
nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) {
|
||||
enum sec_status sec = nsec3_prove_wildcard(env, ve,
|
||||
chase_reply->rrsets+chase_reply->an_numrrsets,
|
||||
chase_reply->ns_numrrsets, qchase, kkey, wc);
|
||||
chase_reply->ns_numrrsets, qchase, kkey, wc,
|
||||
&vq->nsec3_cache_table, nsec3_calculations);
|
||||
if(sec == sec_status_insecure) {
|
||||
verbose(VERB_ALGO, "Positive wildcard response is "
|
||||
"insecure");
|
||||
chase_reply->security = sec_status_insecure;
|
||||
return;
|
||||
} else if(sec == sec_status_secure)
|
||||
} else if(sec == sec_status_secure) {
|
||||
wc_NSEC_ok = 1;
|
||||
} else if(sec == sec_status_unchecked) {
|
||||
*suspend = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If after all this, we still haven't proven the positive wildcard
|
||||
|
@ -904,11 +1061,17 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
|
|||
* @param chase_reply: answer to that query to validate.
|
||||
* @param kkey: the key entry, which is trusted, and which matches
|
||||
* the signer of the answer. The key entry isgood().
|
||||
* @param qstate: query state for the region.
|
||||
* @param vq: validator state for the nsec3 cache table.
|
||||
* @param nsec3_calculations: current nsec3 hash calculations.
|
||||
* @param suspend: returned true if the task takes too long and needs to
|
||||
* suspend to continue the effort later.
|
||||
*/
|
||||
static void
|
||||
validate_nodata_response(struct module_env* env, struct val_env* ve,
|
||||
struct query_info* qchase, struct reply_info* chase_reply,
|
||||
struct key_entry_key* kkey)
|
||||
struct key_entry_key* kkey, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int* nsec3_calculations, int* suspend)
|
||||
{
|
||||
/* Since we are here, there must be nothing in the ANSWER section to
|
||||
* validate. */
|
||||
|
@ -925,6 +1088,7 @@ validate_nodata_response(struct module_env* env, struct val_env* ve,
|
|||
int nsec3s_seen = 0; /* nsec3s seen */
|
||||
struct ub_packed_rrset_key* s;
|
||||
size_t i;
|
||||
*suspend = 0;
|
||||
|
||||
for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
|
||||
chase_reply->ns_numrrsets; i++) {
|
||||
|
@ -963,16 +1127,23 @@ validate_nodata_response(struct module_env* env, struct val_env* ve,
|
|||
}
|
||||
}
|
||||
|
||||
if(!has_valid_nsec && nsec3s_seen) {
|
||||
if(!has_valid_nsec && nsec3s_seen &&
|
||||
nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) {
|
||||
enum sec_status sec = nsec3_prove_nodata(env, ve,
|
||||
chase_reply->rrsets+chase_reply->an_numrrsets,
|
||||
chase_reply->ns_numrrsets, qchase, kkey);
|
||||
chase_reply->ns_numrrsets, qchase, kkey,
|
||||
&vq->nsec3_cache_table, nsec3_calculations);
|
||||
if(sec == sec_status_insecure) {
|
||||
verbose(VERB_ALGO, "NODATA response is insecure");
|
||||
chase_reply->security = sec_status_insecure;
|
||||
return;
|
||||
} else if(sec == sec_status_secure)
|
||||
} else if(sec == sec_status_secure) {
|
||||
has_valid_nsec = 1;
|
||||
} else if(sec == sec_status_unchecked) {
|
||||
/* check is incomplete; suspend */
|
||||
*suspend = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!has_valid_nsec) {
|
||||
|
@ -1004,11 +1175,18 @@ validate_nodata_response(struct module_env* env, struct val_env* ve,
|
|||
* @param kkey: the key entry, which is trusted, and which matches
|
||||
* the signer of the answer. The key entry isgood().
|
||||
* @param rcode: adjusted RCODE, in case of RCODE/proof mismatch leniency.
|
||||
* @param qstate: query state for the region.
|
||||
* @param vq: validator state for the nsec3 cache table.
|
||||
* @param nsec3_calculations: current nsec3 hash calculations.
|
||||
* @param suspend: returned true if the task takes too long and needs to
|
||||
* suspend to continue the effort later.
|
||||
*/
|
||||
static void
|
||||
validate_nameerror_response(struct module_env* env, struct val_env* ve,
|
||||
struct query_info* qchase, struct reply_info* chase_reply,
|
||||
struct key_entry_key* kkey, int* rcode)
|
||||
struct key_entry_key* kkey, int* rcode,
|
||||
struct module_qstate* qstate, struct val_qstate* vq,
|
||||
int* nsec3_calculations, int* suspend)
|
||||
{
|
||||
int has_valid_nsec = 0;
|
||||
int has_valid_wnsec = 0;
|
||||
|
@ -1018,6 +1196,7 @@ validate_nameerror_response(struct module_env* env, struct val_env* ve,
|
|||
uint8_t* ce;
|
||||
int ce_labs = 0;
|
||||
int prev_ce_labs = 0;
|
||||
*suspend = 0;
|
||||
|
||||
for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
|
||||
chase_reply->ns_numrrsets; i++) {
|
||||
|
@ -1047,13 +1226,18 @@ validate_nameerror_response(struct module_env* env, struct val_env* ve,
|
|||
nsec3s_seen = 1;
|
||||
}
|
||||
|
||||
if((!has_valid_nsec || !has_valid_wnsec) && nsec3s_seen) {
|
||||
if((!has_valid_nsec || !has_valid_wnsec) && nsec3s_seen &&
|
||||
nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) {
|
||||
/* use NSEC3 proof, both answer and auth rrsets, in case
|
||||
* NSEC3s end up in the answer (due to qtype=NSEC3 or so) */
|
||||
chase_reply->security = nsec3_prove_nameerror(env, ve,
|
||||
chase_reply->rrsets, chase_reply->an_numrrsets+
|
||||
chase_reply->ns_numrrsets, qchase, kkey);
|
||||
if(chase_reply->security != sec_status_secure) {
|
||||
chase_reply->ns_numrrsets, qchase, kkey,
|
||||
&vq->nsec3_cache_table, nsec3_calculations);
|
||||
if(chase_reply->security == sec_status_unchecked) {
|
||||
*suspend = 1;
|
||||
return;
|
||||
} else if(chase_reply->security != sec_status_secure) {
|
||||
verbose(VERB_QUERY, "NameError response failed nsec, "
|
||||
"nsec3 proof was %s", sec_status_to_string(
|
||||
chase_reply->security));
|
||||
|
@ -1065,26 +1249,34 @@ validate_nameerror_response(struct module_env* env, struct val_env* ve,
|
|||
|
||||
/* If the message fails to prove either condition, it is bogus. */
|
||||
if(!has_valid_nsec) {
|
||||
validate_nodata_response(env, ve, qchase, chase_reply, kkey,
|
||||
qstate, vq, nsec3_calculations, suspend);
|
||||
if(*suspend) return;
|
||||
verbose(VERB_QUERY, "NameError response has failed to prove: "
|
||||
"qname does not exist");
|
||||
chase_reply->security = sec_status_bogus;
|
||||
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
|
||||
/* Be lenient with RCODE in NSEC NameError responses */
|
||||
validate_nodata_response(env, ve, qchase, chase_reply, kkey);
|
||||
if (chase_reply->security == sec_status_secure)
|
||||
if(chase_reply->security == sec_status_secure) {
|
||||
*rcode = LDNS_RCODE_NOERROR;
|
||||
} else {
|
||||
chase_reply->security = sec_status_bogus;
|
||||
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!has_valid_wnsec) {
|
||||
validate_nodata_response(env, ve, qchase, chase_reply, kkey,
|
||||
qstate, vq, nsec3_calculations, suspend);
|
||||
if(*suspend) return;
|
||||
verbose(VERB_QUERY, "NameError response has failed to prove: "
|
||||
"covering wildcard does not exist");
|
||||
chase_reply->security = sec_status_bogus;
|
||||
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
|
||||
/* Be lenient with RCODE in NSEC NameError responses */
|
||||
validate_nodata_response(env, ve, qchase, chase_reply, kkey);
|
||||
if (chase_reply->security == sec_status_secure)
|
||||
if (chase_reply->security == sec_status_secure) {
|
||||
*rcode = LDNS_RCODE_NOERROR;
|
||||
} else {
|
||||
chase_reply->security = sec_status_bogus;
|
||||
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1144,11 +1336,17 @@ validate_referral_response(struct reply_info* chase_reply)
|
|||
* @param chase_reply: answer to that query to validate.
|
||||
* @param kkey: the key entry, which is trusted, and which matches
|
||||
* the signer of the answer. The key entry isgood().
|
||||
* @param qstate: query state for the region.
|
||||
* @param vq: validator state for the nsec3 cache table.
|
||||
* @param nsec3_calculations: current nsec3 hash calculations.
|
||||
* @param suspend: returned true if the task takes too long and needs to
|
||||
* suspend to continue the effort later.
|
||||
*/
|
||||
static void
|
||||
validate_any_response(struct module_env* env, struct val_env* ve,
|
||||
struct query_info* qchase, struct reply_info* chase_reply,
|
||||
struct key_entry_key* kkey)
|
||||
struct key_entry_key* kkey, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int* nsec3_calculations, int* suspend)
|
||||
{
|
||||
/* all answer and auth rrsets already verified */
|
||||
/* but check if a wildcard response is given, then check NSEC/NSEC3
|
||||
|
@ -1159,6 +1357,7 @@ validate_any_response(struct module_env* env, struct val_env* ve,
|
|||
int nsec3s_seen = 0;
|
||||
size_t i;
|
||||
struct ub_packed_rrset_key* s;
|
||||
*suspend = 0;
|
||||
|
||||
if(qchase->qtype != LDNS_RR_TYPE_ANY) {
|
||||
log_err("internal error: ANY validation called for non-ANY");
|
||||
|
@ -1213,19 +1412,25 @@ validate_any_response(struct module_env* env, struct val_env* ve,
|
|||
/* If this was a positive wildcard response that we haven't already
|
||||
* proven, and we have NSEC3 records, try to prove it using the NSEC3
|
||||
* records. */
|
||||
if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) {
|
||||
if(wc != NULL && !wc_NSEC_ok && nsec3s_seen &&
|
||||
nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) {
|
||||
/* look both in answer and auth section for NSEC3s */
|
||||
enum sec_status sec = nsec3_prove_wildcard(env, ve,
|
||||
chase_reply->rrsets,
|
||||
chase_reply->an_numrrsets+chase_reply->ns_numrrsets,
|
||||
qchase, kkey, wc);
|
||||
qchase, kkey, wc, &vq->nsec3_cache_table,
|
||||
nsec3_calculations);
|
||||
if(sec == sec_status_insecure) {
|
||||
verbose(VERB_ALGO, "Positive ANY wildcard response is "
|
||||
"insecure");
|
||||
chase_reply->security = sec_status_insecure;
|
||||
return;
|
||||
} else if(sec == sec_status_secure)
|
||||
} else if(sec == sec_status_secure) {
|
||||
wc_NSEC_ok = 1;
|
||||
} else if(sec == sec_status_unchecked) {
|
||||
*suspend = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If after all this, we still haven't proven the positive wildcard
|
||||
|
@ -1258,11 +1463,17 @@ validate_any_response(struct module_env* env, struct val_env* ve,
|
|||
* @param chase_reply: answer to that query to validate.
|
||||
* @param kkey: the key entry, which is trusted, and which matches
|
||||
* the signer of the answer. The key entry isgood().
|
||||
* @param qstate: query state for the region.
|
||||
* @param vq: validator state for the nsec3 cache table.
|
||||
* @param nsec3_calculations: current nsec3 hash calculations.
|
||||
* @param suspend: returned true if the task takes too long and needs to
|
||||
* suspend to continue the effort later.
|
||||
*/
|
||||
static void
|
||||
validate_cname_response(struct module_env* env, struct val_env* ve,
|
||||
struct query_info* qchase, struct reply_info* chase_reply,
|
||||
struct key_entry_key* kkey)
|
||||
struct key_entry_key* kkey, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int* nsec3_calculations, int* suspend)
|
||||
{
|
||||
uint8_t* wc = NULL;
|
||||
size_t wl;
|
||||
|
@ -1270,6 +1481,7 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
|
|||
int nsec3s_seen = 0;
|
||||
size_t i;
|
||||
struct ub_packed_rrset_key* s;
|
||||
*suspend = 0;
|
||||
|
||||
/* validate the ANSWER section - this will be the CNAME (+DNAME) */
|
||||
for(i=0; i<chase_reply->an_numrrsets; i++) {
|
||||
|
@ -1334,17 +1546,23 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
|
|||
/* If this was a positive wildcard response that we haven't already
|
||||
* proven, and we have NSEC3 records, try to prove it using the NSEC3
|
||||
* records. */
|
||||
if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) {
|
||||
if(wc != NULL && !wc_NSEC_ok && nsec3s_seen &&
|
||||
nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) {
|
||||
enum sec_status sec = nsec3_prove_wildcard(env, ve,
|
||||
chase_reply->rrsets+chase_reply->an_numrrsets,
|
||||
chase_reply->ns_numrrsets, qchase, kkey, wc);
|
||||
chase_reply->ns_numrrsets, qchase, kkey, wc,
|
||||
&vq->nsec3_cache_table, nsec3_calculations);
|
||||
if(sec == sec_status_insecure) {
|
||||
verbose(VERB_ALGO, "wildcard CNAME response is "
|
||||
"insecure");
|
||||
chase_reply->security = sec_status_insecure;
|
||||
return;
|
||||
} else if(sec == sec_status_secure)
|
||||
} else if(sec == sec_status_secure) {
|
||||
wc_NSEC_ok = 1;
|
||||
} else if(sec == sec_status_unchecked) {
|
||||
*suspend = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If after all this, we still haven't proven the positive wildcard
|
||||
|
@ -1375,11 +1593,17 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
|
|||
* @param chase_reply: answer to that query to validate.
|
||||
* @param kkey: the key entry, which is trusted, and which matches
|
||||
* the signer of the answer. The key entry isgood().
|
||||
* @param qstate: query state for the region.
|
||||
* @param vq: validator state for the nsec3 cache table.
|
||||
* @param nsec3_calculations: current nsec3 hash calculations.
|
||||
* @param suspend: returned true if the task takes too long and needs to
|
||||
* suspend to continue the effort later.
|
||||
*/
|
||||
static void
|
||||
validate_cname_noanswer_response(struct module_env* env, struct val_env* ve,
|
||||
struct query_info* qchase, struct reply_info* chase_reply,
|
||||
struct key_entry_key* kkey)
|
||||
struct key_entry_key* kkey, struct module_qstate* qstate,
|
||||
struct val_qstate* vq, int* nsec3_calculations, int* suspend)
|
||||
{
|
||||
int nodata_valid_nsec = 0; /* If true, then NODATA has been proven.*/
|
||||
uint8_t* ce = NULL; /* for wildcard nodata responses. This is the
|
||||
|
@ -1393,6 +1617,7 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve,
|
|||
uint8_t* nsec_ce; /* Used to find the NSEC with the longest ce */
|
||||
int ce_labs = 0;
|
||||
int prev_ce_labs = 0;
|
||||
*suspend = 0;
|
||||
|
||||
/* the AUTHORITY section */
|
||||
for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
|
||||
|
@ -1458,11 +1683,13 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve,
|
|||
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
|
||||
return;
|
||||
}
|
||||
if(!nodata_valid_nsec && !nxdomain_valid_nsec && nsec3s_seen) {
|
||||
if(!nodata_valid_nsec && !nxdomain_valid_nsec && nsec3s_seen &&
|
||||
nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) {
|
||||
int nodata;
|
||||
enum sec_status sec = nsec3_prove_nxornodata(env, ve,
|
||||
chase_reply->rrsets+chase_reply->an_numrrsets,
|
||||
chase_reply->ns_numrrsets, qchase, kkey, &nodata);
|
||||
chase_reply->ns_numrrsets, qchase, kkey, &nodata,
|
||||
&vq->nsec3_cache_table, nsec3_calculations);
|
||||
if(sec == sec_status_insecure) {
|
||||
verbose(VERB_ALGO, "CNAMEchain to noanswer response "
|
||||
"is insecure");
|
||||
|
@ -1472,6 +1699,9 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve,
|
|||
if(nodata)
|
||||
nodata_valid_nsec = 1;
|
||||
else nxdomain_valid_nsec = 1;
|
||||
} else if(sec == sec_status_unchecked) {
|
||||
*suspend = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1815,13 +2045,37 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
|
|||
* Uses negative cache for NSEC3 lookup of DS responses. */
|
||||
/* only if cache not blacklisted, of course */
|
||||
struct dns_msg* msg;
|
||||
if(!qstate->blacklist && !vq->chain_blacklist &&
|
||||
int suspend;
|
||||
if(vq->sub_ds_msg) {
|
||||
/* We have a suspended DS reply from a sub-query;
|
||||
* process it. */
|
||||
verbose(VERB_ALGO, "Process suspended sub DS response");
|
||||
msg = vq->sub_ds_msg;
|
||||
process_ds_response(qstate, vq, id, LDNS_RCODE_NOERROR,
|
||||
msg, &msg->qinfo, NULL, &suspend);
|
||||
if(suspend) {
|
||||
/* we'll come back here later to continue */
|
||||
if(!validate_suspend_setup_timer(qstate, vq,
|
||||
id, VAL_FINDKEY_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
vq->sub_ds_msg = NULL;
|
||||
return 1; /* continue processing ds-response results */
|
||||
} else if(!qstate->blacklist && !vq->chain_blacklist &&
|
||||
(msg=val_find_DS(qstate->env, target_key_name,
|
||||
target_key_len, vq->qchase.qclass, qstate->region,
|
||||
vq->key_entry->name)) ) {
|
||||
verbose(VERB_ALGO, "Process cached DS response");
|
||||
process_ds_response(qstate, vq, id, LDNS_RCODE_NOERROR,
|
||||
msg, &msg->qinfo, NULL);
|
||||
msg, &msg->qinfo, NULL, &suspend);
|
||||
if(suspend) {
|
||||
/* we'll come back here later to continue */
|
||||
if(!validate_suspend_setup_timer(qstate, vq,
|
||||
id, VAL_FINDKEY_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
return 1; /* continue processing ds-response results */
|
||||
}
|
||||
if(!generate_request(qstate, id, target_key_name,
|
||||
|
@ -1864,7 +2118,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
struct val_env* ve, int id)
|
||||
{
|
||||
enum val_classification subtype;
|
||||
int rcode;
|
||||
int rcode, suspend, nsec3_calculations = 0;
|
||||
|
||||
if(!vq->key_entry) {
|
||||
verbose(VERB_ALGO, "validate: no key entry, failed");
|
||||
|
@ -1921,8 +2175,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
|
||||
/* check signatures in the message;
|
||||
* answer and authority must be valid, additional is only checked. */
|
||||
if(!validate_msg_signatures(qstate, qstate->env, ve, &vq->qchase,
|
||||
vq->chase_reply, vq->key_entry)) {
|
||||
if(!validate_msg_signatures(qstate, vq, qstate->env, ve, &vq->qchase,
|
||||
vq->chase_reply, vq->key_entry, &suspend)) {
|
||||
if(suspend) {
|
||||
if(!validate_suspend_setup_timer(qstate, vq,
|
||||
id, VAL_VALIDATE_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
/* workaround bad recursor out there that truncates (even
|
||||
* with EDNS4k) to 512 by removing RRSIG from auth section
|
||||
* for positive replies*/
|
||||
|
@ -1951,7 +2211,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
case VAL_CLASS_POSITIVE:
|
||||
verbose(VERB_ALGO, "Validating a positive response");
|
||||
validate_positive_response(qstate->env, ve,
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry);
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry,
|
||||
qstate, vq, &nsec3_calculations, &suspend);
|
||||
if(suspend) {
|
||||
if(!validate_suspend_setup_timer(qstate,
|
||||
vq, id, VAL_VALIDATE_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_DETAIL, "validate(positive): %s",
|
||||
sec_status_to_string(
|
||||
vq->chase_reply->security));
|
||||
|
@ -1960,7 +2227,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
case VAL_CLASS_NODATA:
|
||||
verbose(VERB_ALGO, "Validating a nodata response");
|
||||
validate_nodata_response(qstate->env, ve,
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry);
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry,
|
||||
qstate, vq, &nsec3_calculations, &suspend);
|
||||
if(suspend) {
|
||||
if(!validate_suspend_setup_timer(qstate,
|
||||
vq, id, VAL_VALIDATE_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_DETAIL, "validate(nodata): %s",
|
||||
sec_status_to_string(
|
||||
vq->chase_reply->security));
|
||||
|
@ -1970,7 +2244,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
rcode = (int)FLAGS_GET_RCODE(vq->orig_msg->rep->flags);
|
||||
verbose(VERB_ALGO, "Validating a nxdomain response");
|
||||
validate_nameerror_response(qstate->env, ve,
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry, &rcode);
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry, &rcode,
|
||||
qstate, vq, &nsec3_calculations, &suspend);
|
||||
if(suspend) {
|
||||
if(!validate_suspend_setup_timer(qstate,
|
||||
vq, id, VAL_VALIDATE_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_DETAIL, "validate(nxdomain): %s",
|
||||
sec_status_to_string(
|
||||
vq->chase_reply->security));
|
||||
|
@ -1981,7 +2262,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
case VAL_CLASS_CNAME:
|
||||
verbose(VERB_ALGO, "Validating a cname response");
|
||||
validate_cname_response(qstate->env, ve,
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry);
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry,
|
||||
qstate, vq, &nsec3_calculations, &suspend);
|
||||
if(suspend) {
|
||||
if(!validate_suspend_setup_timer(qstate,
|
||||
vq, id, VAL_VALIDATE_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_DETAIL, "validate(cname): %s",
|
||||
sec_status_to_string(
|
||||
vq->chase_reply->security));
|
||||
|
@ -1991,7 +2279,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
verbose(VERB_ALGO, "Validating a cname noanswer "
|
||||
"response");
|
||||
validate_cname_noanswer_response(qstate->env, ve,
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry);
|
||||
&vq->qchase, vq->chase_reply, vq->key_entry,
|
||||
qstate, vq, &nsec3_calculations, &suspend);
|
||||
if(suspend) {
|
||||
if(!validate_suspend_setup_timer(qstate,
|
||||
vq, id, VAL_VALIDATE_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_DETAIL, "validate(cname_noanswer): %s",
|
||||
sec_status_to_string(
|
||||
vq->chase_reply->security));
|
||||
|
@ -2009,7 +2304,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
verbose(VERB_ALGO, "Validating a positive ANY "
|
||||
"response");
|
||||
validate_any_response(qstate->env, ve, &vq->qchase,
|
||||
vq->chase_reply, vq->key_entry);
|
||||
vq->chase_reply, vq->key_entry, qstate, vq,
|
||||
&nsec3_calculations, &suspend);
|
||||
if(suspend) {
|
||||
if(!validate_suspend_setup_timer(qstate,
|
||||
vq, id, VAL_VALIDATE_STATE))
|
||||
return val_error(qstate, id);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_DETAIL, "validate(positive_any): %s",
|
||||
sec_status_to_string(
|
||||
vq->chase_reply->security));
|
||||
|
@ -2118,16 +2420,13 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
if(vq->orig_msg->rep->security == sec_status_bogus) {
|
||||
/* see if we can try again to fetch data */
|
||||
if(vq->restart_count < ve->max_restart) {
|
||||
int restart_count = vq->restart_count+1;
|
||||
verbose(VERB_ALGO, "validation failed, "
|
||||
"blacklist and retry to fetch data");
|
||||
val_blacklist(&qstate->blacklist, qstate->region,
|
||||
qstate->reply_origin, 0);
|
||||
qstate->reply_origin = NULL;
|
||||
qstate->errinf = NULL;
|
||||
memset(vq, 0, sizeof(*vq));
|
||||
vq->restart_count = restart_count;
|
||||
vq->state = VAL_INIT_STATE;
|
||||
val_restart(vq);
|
||||
verbose(VERB_ALGO, "pass back to next module");
|
||||
qstate->ext_state[id] = module_restart_next;
|
||||
return 0;
|
||||
|
@ -2454,7 +2753,10 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
|
|||
* DS response indicated an end to secure space, is_good if the DS
|
||||
* validated. It returns ke=NULL if the DS response indicated that the
|
||||
* request wasn't a delegation point.
|
||||
* @return 0 on servfail error (malloc failure).
|
||||
* @return
|
||||
* 0 on success,
|
||||
* 1 on servfail error (malloc failure),
|
||||
* 2 on NSEC3 suspend.
|
||||
*/
|
||||
static int
|
||||
ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
|
@ -2465,6 +2767,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
char* reason = NULL;
|
||||
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
enum val_classification subtype;
|
||||
int verified;
|
||||
if(rcode != LDNS_RCODE_NOERROR) {
|
||||
char rc[16];
|
||||
rc[0]=0;
|
||||
|
@ -2495,7 +2798,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
/* Verify only returns BOGUS or SECURE. If the rrset is
|
||||
* bogus, then we are done. */
|
||||
sec = val_verify_rrset_entry(qstate->env, ve, ds,
|
||||
vq->key_entry, &reason, &reason_bogus, LDNS_SECTION_ANSWER, qstate);
|
||||
vq->key_entry, &reason, &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified);
|
||||
if(sec != sec_status_secure) {
|
||||
verbose(VERB_DETAIL, "DS rrset in DS response did "
|
||||
"not verify");
|
||||
|
@ -2513,7 +2816,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
ub_packed_rrset_ttl(ds),
|
||||
LDNS_EDE_UNSUPPORTED_DS_DIGEST, NULL,
|
||||
*qstate->env->now);
|
||||
return (*ke) != NULL;
|
||||
return (*ke) == NULL;
|
||||
}
|
||||
|
||||
/* Otherwise, we return the positive response. */
|
||||
|
@ -2521,7 +2824,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
*ke = key_entry_create_rrset(qstate->region,
|
||||
qinfo->qname, qinfo->qname_len, qinfo->qclass, ds,
|
||||
NULL, LDNS_EDE_NONE, NULL, *qstate->env->now);
|
||||
return (*ke) != NULL;
|
||||
return (*ke) == NULL;
|
||||
} else if(subtype == VAL_CLASS_NODATA ||
|
||||
subtype == VAL_CLASS_NAMEERROR) {
|
||||
/* NODATA means that the qname exists, but that there was
|
||||
|
@ -2555,12 +2858,12 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
qinfo->qclass, proof_ttl,
|
||||
LDNS_EDE_NONE, NULL,
|
||||
*qstate->env->now);
|
||||
return (*ke) != NULL;
|
||||
return (*ke) == NULL;
|
||||
case sec_status_insecure:
|
||||
verbose(VERB_DETAIL, "NSEC RRset for the "
|
||||
"referral proved not a delegation point");
|
||||
*ke = NULL;
|
||||
return 1;
|
||||
return 0;
|
||||
case sec_status_bogus:
|
||||
verbose(VERB_DETAIL, "NSEC RRset for the "
|
||||
"referral did not prove no DS.");
|
||||
|
@ -2572,10 +2875,17 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
break;
|
||||
}
|
||||
|
||||
if(!nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) {
|
||||
log_err("malloc failure in ds_response_to_ke for "
|
||||
"NSEC3 cache");
|
||||
reason = "malloc failure";
|
||||
errinf_ede(qstate, reason, 0);
|
||||
goto return_bogus;
|
||||
}
|
||||
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);
|
||||
&reason_bogus, qstate, &vq->nsec3_cache_table);
|
||||
switch(sec) {
|
||||
case sec_status_insecure:
|
||||
/* case insecure also continues to unsigned
|
||||
|
@ -2589,18 +2899,19 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
qinfo->qclass, proof_ttl,
|
||||
LDNS_EDE_NONE, NULL,
|
||||
*qstate->env->now);
|
||||
return (*ke) != NULL;
|
||||
return (*ke) == NULL;
|
||||
case sec_status_indeterminate:
|
||||
verbose(VERB_DETAIL, "NSEC3s for the "
|
||||
"referral proved no delegation");
|
||||
*ke = NULL;
|
||||
return 1;
|
||||
return 0;
|
||||
case sec_status_bogus:
|
||||
verbose(VERB_DETAIL, "NSEC3s for the "
|
||||
"referral did not prove no DS.");
|
||||
errinf_ede(qstate, reason, reason_bogus);
|
||||
goto return_bogus;
|
||||
case sec_status_unchecked:
|
||||
return 2;
|
||||
default:
|
||||
/* NSEC3 proof did not work */
|
||||
break;
|
||||
|
@ -2641,13 +2952,13 @@ 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);
|
||||
LDNS_SECTION_ANSWER, qstate, &verified);
|
||||
if(sec == sec_status_secure) {
|
||||
verbose(VERB_ALGO, "CNAME validated, "
|
||||
"proof that DS does not exist");
|
||||
/* and that it is not a referral point */
|
||||
*ke = NULL;
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
errinf(qstate, "CNAME in DS response was not secure.");
|
||||
errinf_ede(qstate, reason, reason_bogus);
|
||||
|
@ -2671,7 +2982,7 @@ return_bogus:
|
|||
*ke = key_entry_create_bad(qstate->region, qinfo->qname,
|
||||
qinfo->qname_len, qinfo->qclass, BOGUS_KEY_TTL,
|
||||
reason_bogus, reason, *qstate->env->now);
|
||||
return (*ke) != NULL;
|
||||
return (*ke) == NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2692,17 +3003,31 @@ return_bogus:
|
|||
static void
|
||||
process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
|
||||
int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
|
||||
struct sock_list* origin)
|
||||
struct sock_list* origin, int* suspend)
|
||||
{
|
||||
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
|
||||
struct key_entry_key* dske = NULL;
|
||||
uint8_t* olds = vq->empty_DS_name;
|
||||
int ret;
|
||||
*suspend = 0;
|
||||
vq->empty_DS_name = NULL;
|
||||
if(!ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske)) {
|
||||
ret = ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske);
|
||||
if(ret != 0) {
|
||||
switch(ret) {
|
||||
case 1:
|
||||
log_err("malloc failure in process_ds_response");
|
||||
vq->key_entry = NULL; /* make it error */
|
||||
vq->state = VAL_VALIDATE_STATE;
|
||||
return;
|
||||
case 2:
|
||||
*suspend = 1;
|
||||
return;
|
||||
default:
|
||||
log_err("unhandled error value for ds_response_to_ke");
|
||||
vq->key_entry = NULL; /* make it error */
|
||||
vq->state = VAL_VALIDATE_STATE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(dske == NULL) {
|
||||
vq->empty_DS_name = regional_alloc_init(qstate->region,
|
||||
|
@ -2954,9 +3279,26 @@ val_inform_super(struct module_qstate* qstate, int id,
|
|||
return;
|
||||
}
|
||||
if(qstate->qinfo.qtype == LDNS_RR_TYPE_DS) {
|
||||
int suspend;
|
||||
process_ds_response(super, vq, id, qstate->return_rcode,
|
||||
qstate->return_msg, &qstate->qinfo,
|
||||
qstate->reply_origin);
|
||||
qstate->reply_origin, &suspend);
|
||||
/* If NSEC3 was needed during validation, NULL the NSEC3 cache;
|
||||
* it will be re-initiated if needed later on.
|
||||
* Validation (and the cache table) are happening/allocated in
|
||||
* the super qstate whilst the RRs are allocated (and pointed
|
||||
* to) in this sub qstate. */
|
||||
if(vq->nsec3_cache_table.ct) {
|
||||
vq->nsec3_cache_table.ct = NULL;
|
||||
}
|
||||
if(suspend) {
|
||||
/* deep copy the return_msg to vq->sub_ds_msg; it will
|
||||
* be resumed later in the super state with the caveat
|
||||
* that the initial calculations will be re-caclulated
|
||||
* and re-suspended there before continuing. */
|
||||
vq->sub_ds_msg = dns_msg_deepcopy_region(
|
||||
qstate->return_msg, super->region);
|
||||
}
|
||||
return;
|
||||
} else if(qstate->qinfo.qtype == LDNS_RR_TYPE_DNSKEY) {
|
||||
process_dnskey_response(super, vq, id, qstate->return_rcode,
|
||||
|
@ -2970,8 +3312,15 @@ val_inform_super(struct module_qstate* qstate, int id,
|
|||
void
|
||||
val_clear(struct module_qstate* qstate, int id)
|
||||
{
|
||||
struct val_qstate* vq;
|
||||
if(!qstate)
|
||||
return;
|
||||
vq = (struct val_qstate*)qstate->minfo[id];
|
||||
if(vq) {
|
||||
if(vq->suspend_timer) {
|
||||
comm_timer_delete(vq->suspend_timer);
|
||||
}
|
||||
}
|
||||
/* everything is allocated in the region, so assign NULL */
|
||||
qstate->minfo[id] = NULL;
|
||||
}
|
||||
|
|
|
@ -45,11 +45,13 @@
|
|||
#include "util/module.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "validator/val_utils.h"
|
||||
#include "validator/val_nsec3.h"
|
||||
struct val_anchors;
|
||||
struct key_cache;
|
||||
struct key_entry_key;
|
||||
struct val_neg_cache;
|
||||
struct config_strlist;
|
||||
struct comm_timer;
|
||||
|
||||
/**
|
||||
* This is the TTL to use when a trust anchor fails to prime. A trust anchor
|
||||
|
@ -215,6 +217,19 @@ struct val_qstate {
|
|||
|
||||
/** true if this state is waiting to prime a trust anchor */
|
||||
int wait_prime_ta;
|
||||
|
||||
/** State to continue with RRSIG validation in a message later */
|
||||
int msg_signatures_state;
|
||||
/** The rrset index for the msg signatures to continue from */
|
||||
size_t msg_signatures_index;
|
||||
/** Cache table for NSEC3 hashes */
|
||||
struct nsec3_cache_table nsec3_cache_table;
|
||||
/** DS message from sub if it got suspended from NSEC3 calculations */
|
||||
struct dns_msg* sub_ds_msg;
|
||||
/** The timer to resume processing msg signatures */
|
||||
struct comm_timer* suspend_timer;
|
||||
/** Number of suspends */
|
||||
int suspend_count;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -262,4 +277,7 @@ void val_clear(struct module_qstate* qstate, int id);
|
|||
*/
|
||||
size_t val_get_mem(struct module_env* env, int id);
|
||||
|
||||
/** Timer callback for msg signatures continue timer */
|
||||
void validate_suspend_timer_cb(void* arg);
|
||||
|
||||
#endif /* VALIDATOR_VALIDATOR_H */
|
||||
|
|
Loading…
Reference in New Issue